ca760bc603c908e11b7e5048bb34532205e04653
[openwrt.git] / target / linux / beagleboard / patches-2.6.32 / 001-DSS2.patch
1 diff --git a/Documentation/arm/OMAP/DSS b/Documentation/arm/OMAP/DSS
2 new file mode 100644
3 index 0000000..0af0e9e
4 --- /dev/null
5 +++ b/Documentation/arm/OMAP/DSS
6 @@ -0,0 +1,317 @@
7 +OMAP2/3 Display Subsystem
8 +-------------------------
9 +
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
13 +also.
14 +
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.
18 +
19 +Features
20 +--------
21 +
22 +Working and tested features include:
23 +
24 +- MIPI DPI (parallel) output
25 +- MIPI DSI output in command mode
26 +- MIPI DBI (RFBI) output
27 +- SDI output
28 +- TV 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
32 +- OMAP DISPC planes
33 +- RGB16, RGB24 packed, RGB24 unpacked
34 +- YUV2, UYVY
35 +- Scaling
36 +- Adjusting DSS FCK to find a good pixel clock
37 +- Use DSI DPLL to create DSS FCK
38 +
39 +Tested boards include:
40 +- OMAP3 SDP board
41 +- Beagle board
42 +- N810
43 +
44 +omapdss driver
45 +--------------
46 +
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
49 +drivers can use.
50 +
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.
55 +
56 +Panel and controller drivers
57 +----------------------------
58 +
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.
62 +
63 +omapfb driver
64 +-------------
65 +
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.
69 +
70 +The driver exports some omapfb specific ioctls, which are compatible with the
71 +ioctls in the old driver.
72 +
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.
75 +
76 +V4L2 drivers
77 +------------
78 +
79 +V4L2 is being implemented in TI.
80 +
81 +From omapdss point of view the V4L2 drivers should be similar to framebuffer
82 +driver.
83 +
84 +Architecture
85 +--------------------
86 +
87 +Some clarification what the different components do:
88 +
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
91 + depth.
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
97 + display.
98 + - Display is the actual physical display device.
99 +
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.
104 +
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.
108 +
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:
111 +
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
115 + display.
116 +
117 +Sysfs
118 +-----
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.
122 +
123 +The sysfs interface is divided to two parts: DSS and FB.
124 +
125 +/sys/class/graphics/fb? directory:
126 +mirror 0=off, 1=on
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
133 +
134 +/sys/devices/platform/omapdss/overlay? directory:
135 +enabled 0=off, 1=on
136 +input_size width,height (ie. the framebuffer size)
137 +manager Destination overlay manager name
138 +name
139 +output_size width,height
140 +position x,y
141 +screen_width width
142 +global_alpha global alpha 0-255 0=transparent 255=opaque
143 +
144 +/sys/devices/platform/omapdss/manager? directory:
145 +display Destination display
146 +name
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)
152 +
153 +/sys/devices/platform/omapdss/display? directory:
154 +ctrl_name Controller name
155 +mirror 0=off, 1=on
156 +update_mode 0=off, 1=auto, 2=manual
157 +enabled 0=off, 1=on
158 +name
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:
162 + "pal" and "ntsc"
163 +panel_name
164 +tear_elim Tearing elimination 0=off, 1=on
165 +
166 +There are also some debugfs files at <debugfs>/omapdss/ which show information
167 +about clocks and registers.
168 +
169 +Examples
170 +--------
171 +
172 +The following definitions have been made for the examples below:
173 +
174 +ovl0=/sys/devices/platform/omapdss/overlay0
175 +ovl1=/sys/devices/platform/omapdss/overlay1
176 +ovl2=/sys/devices/platform/omapdss/overlay2
177 +
178 +mgr0=/sys/devices/platform/omapdss/manager0
179 +mgr1=/sys/devices/platform/omapdss/manager1
180 +
181 +lcd=/sys/devices/platform/omapdss/display0
182 +dvi=/sys/devices/platform/omapdss/display1
183 +tv=/sys/devices/platform/omapdss/display2
184 +
185 +fb0=/sys/class/graphics/fb0
186 +fb1=/sys/class/graphics/fb1
187 +fb2=/sys/class/graphics/fb2
188 +
189 +Default setup on OMAP3 SDP
190 +--------------------------
191 +
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.
196 +
197 +FB0 --- GFX -\ DVI
198 +FB1 --- VID1 --+- LCD ---- LCD
199 +FB2 --- VID2 -/ TV ----- TV
200 +
201 +Example: Switch from LCD to DVI
202 +----------------------
203 +
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`
206 +
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
213 +
214 +After this the configuration looks like:
215 +
216 +FB0 --- GFX -\ -- DVI
217 +FB1 --- VID1 --+- LCD -/ LCD
218 +FB2 --- VID2 -/ TV ----- TV
219 +
220 +Example: Clone GFX overlay to LCD and TV
221 +-------------------------------
222 +
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`
225 +
226 +echo "0" > $ovl0/enabled
227 +echo "0" > $ovl1/enabled
228 +
229 +echo "" > $fb1/overlays
230 +echo "0,1" > $fb0/overlays
231 +
232 +echo "$w,$h" > $ovl1/output_size
233 +echo "tv" > $ovl1/manager
234 +
235 +echo "1" > $ovl0/enabled
236 +echo "1" > $ovl1/enabled
237 +
238 +echo "1" > $tv/enabled
239 +
240 +After this the configuration looks like (only relevant parts shown):
241 +
242 +FB0 +-- GFX ---- LCD ---- LCD
243 + \- VID1 ---- TV ---- TV
244 +
245 +Misc notes
246 +----------
247 +
248 +OMAP FB allocates the framebuffer memory using the OMAP VRAM allocator.
249 +
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.
252 +
253 +Rotation and mirroring currently only supports RGB565 and RGB8888 modes. VRFB
254 +does not support mirroring.
255 +
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.
260 +
261 +Kernel boot arguments
262 +---------------------
263 +
264 +vram=<size>
265 + - Amount of total VRAM to preallocate. For example, "10M". omapfb
266 + allocates memory for framebuffers from VRAM.
267 +
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.
273 +
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.
279 +
280 +omapfb.debug=<y|n>
281 + - Enable debug printing. You have to have OMAPFB debug support enabled
282 + in kernel config.
283 +
284 +omapfb.test=<y|n>
285 + - Draw test pattern to framebuffer whenever framebuffer settings change.
286 + You need to have OMAPFB debug support enabled in kernel config.
287 +
288 +omapfb.vrfb=<y|n>
289 + - Use VRFB rotation for all framebuffers.
290 +
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
297 +
298 +omapfb.mirror=<y|n>
299 + - Default mirror for all framebuffers. Only works with DMA rotation.
300 +
301 +omapdss.def_disp=<display>
302 + - Name of default display, to which all overlays will be connected.
303 + Common examples are "lcd" or "tv".
304 +
305 +omapdss.debug=<y|n>
306 + - Enable debug printing. You have to have DSS debug support enabled in
307 + kernel config.
308 +
309 +TODO
310 +----
311 +
312 +DSS locking
313 +
314 +Error checking
315 +- Lots of checks are missing or implemented just as BUG()
316 +
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?)
320 +
321 +OMAP1 support
322 +- Not sure if needed
323 +
324 diff --git a/MAINTAINERS b/MAINTAINERS
325 index 8824115..3f5d39f 100644
326 --- a/MAINTAINERS
327 +++ b/MAINTAINERS
328 @@ -3819,6 +3819,23 @@ L: linux-omap@vger.kernel.org
329 S: Maintained
330 F: drivers/video/omap/
331
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
336 +S: Maintained
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
341 +
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
346 +S: Maintained
347 +F: drivers/video/omap2/omapfb/
348 +
349 OMAP MMC SUPPORT
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
357 #
358 # CONFIG_FB_S1D13XXX is not set
359 # CONFIG_FB_VIRTUAL is not set
360 -CONFIG_FB_OMAP=y
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
368 +CONFIG_OMAP2_VRAM=y
369 +CONFIG_OMAP2_VRFB=y
370 +CONFIG_OMAP2_DSS=y
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
379 +CONFIG_FB_OMAP2=y
380 +CONFIG_FB_OMAP2_DEBUG_SUPPORT=y
381 +# CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE is not set
382 +CONFIG_FB_OMAP2_NUM_FBS=3
383 +
384 +#
385 +# OMAP2/3 Display Device Drivers
386 +#
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
391
392 #
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
397 @@ -14,6 +14,7 @@
398 #include <linux/platform_device.h>
399 #include <linux/input.h>
400 #include <linux/clk.h>
401 +#include <linux/omapfb.h>
402
403 #include <linux/spi/spi.h>
404 #include <linux/spi/ads7846.h>
405 @@ -32,7 +33,6 @@
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
417 @@ -36,6 +36,7 @@
418 #include <mach/common.h>
419 #include <mach/dma.h>
420 #include <mach/gpmc.h>
421 +#include <mach/display.h>
422
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 = {
426 },
427 };
428
429 -static struct platform_device sdp3430_lcd_device = {
430 - .name = "sdp2430_lcd",
431 - .id = -1,
432 +
433 +#define SDP3430_LCD_PANEL_BACKLIGHT_GPIO 8
434 +#define SDP3430_LCD_PANEL_ENABLE_GPIO 5
435 +
436 +static unsigned backlight_gpio;
437 +static unsigned enable_gpio;
438 +static int lcd_enabled;
439 +static int dvi_enabled;
440 +
441 +static void __init sdp3430_display_init(void)
442 +{
443 + int r;
444 +
445 + enable_gpio = SDP3430_LCD_PANEL_ENABLE_GPIO;
446 + backlight_gpio = SDP3430_LCD_PANEL_BACKLIGHT_GPIO;
447 +
448 + r = gpio_request(enable_gpio, "LCD reset");
449 + if (r) {
450 + printk(KERN_ERR "failed to get LCD reset GPIO\n");
451 + goto err0;
452 + }
453 +
454 + r = gpio_request(backlight_gpio, "LCD Backlight");
455 + if (r) {
456 + printk(KERN_ERR "failed to get LCD backlight GPIO\n");
457 + goto err1;
458 + }
459 +
460 + gpio_direction_output(enable_gpio, 0);
461 + gpio_direction_output(backlight_gpio, 0);
462 +
463 + return;
464 +err1:
465 + gpio_free(enable_gpio);
466 +err0:
467 + return;
468 +}
469 +
470 +static int sdp3430_panel_enable_lcd(struct omap_dss_device *dssdev)
471 +{
472 + if (dvi_enabled) {
473 + printk(KERN_ERR "cannot enable LCD, DVI is enabled\n");
474 + return -EINVAL;
475 + }
476 +
477 + gpio_direction_output(enable_gpio, 1);
478 + gpio_direction_output(backlight_gpio, 1);
479 +
480 + lcd_enabled = 1;
481 +
482 + return 0;
483 +}
484 +
485 +static void sdp3430_panel_disable_lcd(struct omap_dss_device *dssdev)
486 +{
487 + lcd_enabled = 0;
488 +
489 + gpio_direction_output(enable_gpio, 0);
490 + gpio_direction_output(backlight_gpio, 0);
491 +}
492 +
493 +static int sdp3430_panel_enable_dvi(struct omap_dss_device *dssdev)
494 +{
495 + if (lcd_enabled) {
496 + printk(KERN_ERR "cannot enable DVI, LCD is enabled\n");
497 + return -EINVAL;
498 + }
499 +
500 + dvi_enabled = 1;
501 +
502 + return 0;
503 +}
504 +
505 +static void sdp3430_panel_disable_dvi(struct omap_dss_device *dssdev)
506 +{
507 + dvi_enabled = 0;
508 +}
509 +
510 +static int sdp3430_panel_enable_tv(struct omap_dss_device *dssdev)
511 +{
512 + return 0;
513 +}
514 +
515 +static void sdp3430_panel_disable_tv(struct omap_dss_device *dssdev)
516 +{
517 +}
518 +
519 +
520 +static struct omap_dss_device sdp3430_lcd_device = {
521 + .name = "lcd",
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,
527 };
528
529 -static struct regulator_consumer_supply sdp3430_vdac_supply = {
530 - .supply = "vdac",
531 - .dev = &sdp3430_lcd_device.dev,
532 +static struct omap_dss_device sdp3430_dvi_device = {
533 + .name = "dvi",
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,
539 };
540
541 -static struct regulator_consumer_supply sdp3430_vdvi_supply = {
542 - .supply = "vdvi",
543 - .dev = &sdp3430_lcd_device.dev,
544 +static struct omap_dss_device sdp3430_tv_device = {
545 + .name = "tv",
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,
551 };
552
553 -static struct platform_device *sdp3430_devices[] __initdata = {
554 +
555 +static struct omap_dss_device *sdp3430_dss_devices[] = {
556 &sdp3430_lcd_device,
557 + &sdp3430_dvi_device,
558 + &sdp3430_tv_device,
559 };
560
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,
567 +};
568 +
569 +static struct platform_device sdp3430_dss_device = {
570 + .name = "omapdss",
571 + .id = -1,
572 + .dev = {
573 + .platform_data = &sdp3430_dss_data,
574 + },
575 +};
576 +
577 +static struct regulator_consumer_supply sdp3430_vdda_dac_supply = {
578 + .supply = "vdda_dac",
579 + .dev = &sdp3430_dss_device.dev,
580 +};
581 +
582 +static struct platform_device *sdp3430_devices[] __initdata = {
583 + &sdp3430_dss_device,
584 };
585
586 static struct omap_board_config_kernel sdp3430_config[] __initdata = {
587 - { OMAP_TAG_LCD, &sdp3430_lcd_config },
588 };
589
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,
593 },
594 .num_consumer_supplies = 1,
595 - .consumer_supplies = &sdp3430_vdac_supply,
596 + .consumer_supplies = &sdp3430_vdda_dac_supply,
597 };
598
599 /* VPLL2 for digital video outputs */
600 +static struct regulator_consumer_supply sdp3430_vpll2_supplies[] = {
601 + {
602 + .supply = "vdvi",
603 + .dev = &sdp3430_lcd_device.dev,
604 + },
605 + {
606 + .supply = "vdds_dsi",
607 + .dev = &sdp3430_dss_device.dev,
608 + }
609 +};
610 +
611 static struct regulator_init_data sdp3430_vpll2 = {
612 .constraints = {
613 .name = "VDVI",
614 .min_uV = 1800000,
615 .max_uV = 1800000,
616 + .apply_uV = true,
617 .valid_modes_mask = REGULATOR_MODE_NORMAL
618 | REGULATOR_MODE_STANDBY,
619 .valid_ops_mask = REGULATOR_CHANGE_MODE
620 | REGULATOR_CHANGE_STATUS,
621 },
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,
626 };
627
628 static struct twl4030_platform_data sdp3430_twldata = {
629 @@ -499,6 +633,7 @@ static void __init omap_3430sdp_init(void)
630 omap_serial_init();
631 usb_musb_init();
632 board_smc91x_init();
633 + sdp3430_display_init();
634 enable_board_wakeup_source();
635 }
636
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
685 @@ -22,17 +22,18 @@
686 #include <linux/init.h>
687 #include <linux/io.h>
688 #include <linux/clk.h>
689 +#include <linux/omapfb.h>
690
691 #include <asm/tlb.h>
692
693 #include <asm/mach/map.h>
694
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>
702
703 #ifndef CONFIG_ARCH_OMAP4 /* FIXME: Remove this once clkdev is ready */
704 #include "clock.h"
705 @@ -246,6 +247,7 @@ void __init omap2_map_common_io(void)
706 omap2_check_revision();
707 omap_sram_init();
708 omapfb_reserve_sdram();
709 + omap_vram_reserve_sdram();
710 }
711
712 /*
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);
720 }
721 +
722 +void omap2_sms_write_rot_control(u32 val, unsigned ctx)
723 +{
724 + sms_write_reg(val, SMS_ROT_CONTROL(ctx));
725 +}
726 +
727 +void omap2_sms_write_rot_size(u32 val, unsigned ctx)
728 +{
729 + sms_write_reg(val, SMS_ROT_SIZE(ctx));
730 +}
731 +
732 +void omap2_sms_write_rot_physical_ba(u32 val, unsigned ctx)
733 +{
734 + sms_write_reg(val, SMS_ROT_PHYSICAL_BA(ctx));
735 +}
736 +
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
741 @@ -28,13 +28,13 @@
742 #include <linux/platform_device.h>
743 #include <linux/bootmem.h>
744 #include <linux/io.h>
745 +#include <linux/omapfb.h>
746
747 #include <mach/hardware.h>
748 #include <asm/mach/map.h>
749
750 #include <mach/board.h>
751 #include <mach/sram.h>
752 -#include <mach/omapfb.h>
753
754 #if defined(CONFIG_FB_OMAP) || defined(CONFIG_FB_OMAP_MODULE)
755
756 @@ -327,7 +327,33 @@ static inline int omap_init_fb(void)
757
758 arch_initcall(omap_init_fb);
759
760 -#else
761 +#elif defined(CONFIG_FB_OMAP2) || defined(CONFIG_FB_OMAP2_MODULE)
762 +
763 +static u64 omap_fb_dma_mask = ~(u32)0;
764 +static struct omapfb_platform_data omapfb_config;
765 +
766 +static struct platform_device omap_fb_device = {
767 + .name = "omapfb",
768 + .id = -1,
769 + .dev = {
770 + .dma_mask = &omap_fb_dma_mask,
771 + .coherent_dma_mask = ~(u32)0,
772 + .platform_data = &omapfb_config,
773 + },
774 + .num_resources = 0,
775 +};
776 +
777 +void omapfb_set_platform_data(struct omapfb_platform_data *data)
778 +{
779 + omapfb_config = *data;
780 +}
781 +
782 +static inline int omap_init_fb(void)
783 +{
784 + return platform_device_register(&omap_fb_device);
785 +}
786 +
787 +arch_initcall(omap_init_fb);
788
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,
792 return 0;
793 }
794
795 +#else
796 +
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)
803 +{
804 + return 0;
805 +}
806
807 #endif
808 diff --git a/arch/arm/plat-omap/include/mach/display.h b/arch/arm/plat-omap/include/mach/display.h
809 new file mode 100644
810 index 0000000..4c7422e
811 --- /dev/null
812 +++ b/arch/arm/plat-omap/include/mach/display.h
813 @@ -0,0 +1,540 @@
814 +/*
815 + * linux/include/asm-arm/arch-omap/display.h
816 + *
817 + * Copyright (C) 2008 Nokia Corporation
818 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
819 + *
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.
823 + *
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
827 + * more details.
828 + *
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/>.
831 + */
832 +
833 +#ifndef __ASM_ARCH_OMAP_DISPLAY_H
834 +#define __ASM_ARCH_OMAP_DISPLAY_H
835 +
836 +#include <linux/list.h>
837 +#include <linux/kobject.h>
838 +#include <linux/device.h>
839 +#include <asm/atomic.h>
840 +
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)
858 +
859 +struct omap_dss_device;
860 +struct omap_overlay_manager;
861 +
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,
869 +};
870 +
871 +enum omap_plane {
872 + OMAP_DSS_GFX = 0,
873 + OMAP_DSS_VIDEO1 = 1,
874 + OMAP_DSS_VIDEO2 = 2
875 +};
876 +
877 +enum omap_channel {
878 + OMAP_DSS_CHANNEL_LCD = 0,
879 + OMAP_DSS_CHANNEL_DIGIT = 1,
880 +};
881 +
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 */
897 +
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,
905 +
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,
912 +};
913 +
914 +enum omap_lcd_display_type {
915 + OMAP_DSS_LCD_DISPLAY_STN,
916 + OMAP_DSS_LCD_DISPLAY_TFT,
917 +};
918 +
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,
924 +};
925 +
926 +enum omap_dss_trans_key_type {
927 + OMAP_DSS_COLOR_KEY_GFX_DST = 0,
928 + OMAP_DSS_COLOR_KEY_VID_SRC = 1,
929 +};
930 +
931 +enum omap_rfbi_te_mode {
932 + OMAP_DSS_RFBI_TE_MODE_1 = 1,
933 + OMAP_DSS_RFBI_TE_MODE_2 = 2,
934 +};
935 +
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,
943 +
944 + OMAP_DSS_LCD_TFT = 1<<20,
945 +};
946 +
947 +enum omap_dss_venc_type {
948 + OMAP_DSS_VENC_TYPE_COMPOSITE,
949 + OMAP_DSS_VENC_TYPE_SVIDEO,
950 +};
951 +
952 +enum omap_display_caps {
953 + OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE = 1 << 0,
954 +};
955 +
956 +enum omap_dss_update_mode {
957 + OMAP_DSS_UPDATE_DISABLED = 0,
958 + OMAP_DSS_UPDATE_AUTO,
959 + OMAP_DSS_UPDATE_MANUAL,
960 +};
961 +
962 +enum omap_dss_display_state {
963 + OMAP_DSS_DISPLAY_DISABLED = 0,
964 + OMAP_DSS_DISPLAY_ACTIVE,
965 + OMAP_DSS_DISPLAY_SUSPENDED,
966 +};
967 +
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,
972 +};
973 +
974 +enum omap_dss_rotation_type {
975 + OMAP_DSS_ROT_DMA = 0,
976 + OMAP_DSS_ROT_VRFB = 1,
977 +};
978 +
979 +enum omap_overlay_caps {
980 + OMAP_DSS_OVL_CAP_SCALE = 1 << 0,
981 + OMAP_DSS_OVL_CAP_DISPC = 1 << 1,
982 +};
983 +
984 +enum omap_overlay_manager_caps {
985 + OMAP_DSS_OVL_MGR_CAP_DISPC = 1 << 0,
986 +};
987 +
988 +/* RFBI */
989 +
990 +struct rfbi_timings {
991 + int cs_on_time;
992 + int cs_off_time;
993 + int we_on_time;
994 + int we_off_time;
995 + int re_on_time;
996 + int re_off_time;
997 + int we_cycle_time;
998 + int re_cycle_time;
999 + int cs_pulse_width;
1000 + int access_time;
1001 +
1002 + int clk_div;
1003 +
1004 + u32 tim[5]; /* set by rfbi_convert_timings() */
1005 +
1006 + int converted;
1007 +};
1008 +
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,
1013 + u16 x, u16 y,
1014 + u16 w, u16 h);
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);
1019 +
1020 +/* DSI */
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);
1029 +
1030 +/* Board specific data */
1031 +struct omap_dss_board_info {
1032 + int (*get_last_off_on_transaction_id)(struct device *dev);
1033 + int num_devices;
1034 + struct omap_dss_device **devices;
1035 + struct omap_dss_device *default_device;
1036 +};
1037 +
1038 +struct omap_video_timings {
1039 + /* Unit: pixels */
1040 + u16 x_res;
1041 + /* Unit: pixels */
1042 + u16 y_res;
1043 + /* Unit: KHz */
1044 + u32 pixel_clock;
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 */
1057 +};
1058 +
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;
1066 +#endif
1067 +
1068 +struct omap_overlay_info {
1069 + bool enabled;
1070 +
1071 + u32 paddr;
1072 + void __iomem *vaddr;
1073 + u16 screen_width;
1074 + u16 width;
1075 + u16 height;
1076 + enum omap_color_mode color_mode;
1077 + u8 rotation;
1078 + enum omap_dss_rotation_type rotation_type;
1079 + bool mirror;
1080 +
1081 + u16 pos_x;
1082 + u16 pos_y;
1083 + u16 out_width; /* if 0, out_width == width */
1084 + u16 out_height; /* if 0, out_height == height */
1085 + u8 global_alpha;
1086 +};
1087 +
1088 +struct omap_overlay {
1089 + struct kobject kobj;
1090 + struct list_head list;
1091 +
1092 + /* static fields */
1093 + const char *name;
1094 + int id;
1095 + enum omap_color_mode supported_modes;
1096 + enum omap_overlay_caps caps;
1097 +
1098 + /* dynamic fields */
1099 + struct omap_overlay_manager *manager;
1100 + struct omap_overlay_info info;
1101 +
1102 + /* if true, info has been changed, but not applied() yet */
1103 + bool info_dirty;
1104 +
1105 + int (*set_manager)(struct omap_overlay *ovl,
1106 + struct omap_overlay_manager *mgr);
1107 + int (*unset_manager)(struct omap_overlay *ovl);
1108 +
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);
1113 +
1114 + int (*wait_for_go)(struct omap_overlay *ovl);
1115 +};
1116 +
1117 +struct omap_overlay_manager_info {
1118 + u32 default_color;
1119 +
1120 + enum omap_dss_trans_key_type trans_key_type;
1121 + u32 trans_key;
1122 + bool trans_enabled;
1123 +
1124 + bool alpha_enabled;
1125 +};
1126 +
1127 +struct omap_overlay_manager {
1128 + struct kobject kobj;
1129 + struct list_head list;
1130 +
1131 + /* static fields */
1132 + const char *name;
1133 + int id;
1134 + enum omap_overlay_manager_caps caps;
1135 + int num_overlays;
1136 + struct omap_overlay **overlays;
1137 + enum omap_display_type supported_displays;
1138 +
1139 + /* dynamic fields */
1140 + struct omap_dss_device *device;
1141 + struct omap_overlay_manager_info info;
1142 +
1143 + bool device_changed;
1144 + /* if true, info has been changed but not applied() yet */
1145 + bool info_dirty;
1146 +
1147 + int (*set_device)(struct omap_overlay_manager *mgr,
1148 + struct omap_dss_device *dssdev);
1149 + int (*unset_device)(struct omap_overlay_manager *mgr);
1150 +
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);
1155 +
1156 + int (*apply)(struct omap_overlay_manager *mgr);
1157 + int (*wait_for_go)(struct omap_overlay_manager *mgr);
1158 +};
1159 +
1160 +struct omap_dss_device {
1161 + struct device dev;
1162 +
1163 + enum omap_display_type type;
1164 +
1165 + union {
1166 + struct {
1167 + u8 data_lines;
1168 + } dpi;
1169 +
1170 + struct {
1171 + u8 channel;
1172 + u8 data_lines;
1173 + } rfbi;
1174 +
1175 + struct {
1176 + u8 datapairs;
1177 + } sdi;
1178 +
1179 + struct {
1180 + u8 clk_lane;
1181 + u8 clk_pol;
1182 + u8 data1_lane;
1183 + u8 data1_pol;
1184 + u8 data2_lane;
1185 + u8 data2_pol;
1186 + unsigned long lp_clk_hz;
1187 + unsigned long ddr_clk_hz;
1188 +
1189 + bool ext_te;
1190 + u8 ext_te_gpio;
1191 + } dsi;
1192 +
1193 + struct {
1194 + enum omap_dss_venc_type type;
1195 + bool invert_polarity;
1196 + } venc;
1197 + } phy;
1198 +
1199 + struct {
1200 + struct omap_video_timings timings;
1201 +
1202 + int acbi; /* ac-bias pin transitions per interrupt */
1203 + /* Unit: line clocks */
1204 + int acb; /* ac-bias pin frequency */
1205 +
1206 + enum omap_panel_config config;
1207 +
1208 + u8 recommended_bpp;
1209 +
1210 + struct omap_dss_device *ctrl;
1211 + } panel;
1212 +
1213 + struct {
1214 + u8 pixel_size;
1215 + struct rfbi_timings rfbi_timings;
1216 + struct omap_dss_device *panel;
1217 + } ctrl;
1218 +
1219 + int reset_gpio;
1220 +
1221 + int max_backlight_level;
1222 +
1223 + const char *name;
1224 +
1225 + /* used to match device to driver */
1226 + const char *driver_name;
1227 +
1228 + void *data;
1229 +
1230 + struct omap_dss_driver *driver;
1231 +
1232 + /* helper variable for driver suspend/resume */
1233 + bool activate_after_resume;
1234 +
1235 + enum omap_display_caps caps;
1236 +
1237 + struct omap_overlay_manager *manager;
1238 +
1239 + enum omap_dss_display_state state;
1240 +
1241 + int (*enable)(struct omap_dss_device *dssdev);
1242 + void (*disable)(struct omap_dss_device *dssdev);
1243 +
1244 + int (*suspend)(struct omap_dss_device *dssdev);
1245 + int (*resume)(struct omap_dss_device *dssdev);
1246 +
1247 + void (*get_resolution)(struct omap_dss_device *dssdev,
1248 + u16 *xres, u16 *yres);
1249 + int (*get_recommended_bpp)(struct omap_dss_device *dssdev);
1250 +
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);
1261 +
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);
1266 +
1267 + int (*enable_te)(struct omap_dss_device *dssdev, bool enable);
1268 + int (*get_te)(struct omap_dss_device *dssdev);
1269 +
1270 + u8 (*get_rotate)(struct omap_dss_device *dssdev);
1271 + int (*set_rotate)(struct omap_dss_device *dssdev, u8 rotate);
1272 +
1273 + bool (*get_mirror)(struct omap_dss_device *dssdev);
1274 + int (*set_mirror)(struct omap_dss_device *dssdev, bool enable);
1275 +
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);
1280 +
1281 + int (*set_wss)(struct omap_dss_device *dssdev, u32 wss);
1282 + u32 (*get_wss)(struct omap_dss_device *dssdev);
1283 +
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);
1289 +};
1290 +
1291 +struct omap_dss_driver {
1292 + struct device_driver driver;
1293 +
1294 + int (*probe)(struct omap_dss_device *);
1295 + void (*remove)(struct omap_dss_device *);
1296 +
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);
1302 +
1303 + void (*setup_update)(struct omap_dss_device *dssdev,
1304 + u16 x, u16 y, u16 w, u16 h);
1305 +
1306 + int (*enable_te)(struct omap_dss_device *dssdev, bool enable);
1307 + int (*wait_for_te)(struct omap_dss_device *dssdev);
1308 +
1309 + u8 (*get_rotate)(struct omap_dss_device *dssdev);
1310 + int (*set_rotate)(struct omap_dss_device *dssdev, u8 rotate);
1311 +
1312 + bool (*get_mirror)(struct omap_dss_device *dssdev);
1313 + int (*set_mirror)(struct omap_dss_device *dssdev, bool enable);
1314 +
1315 + int (*memory_read)(struct omap_dss_device *dssdev,
1316 + void *buf, size_t size,
1317 + u16 x, u16 y, u16 w, u16 h);
1318 +};
1319 +
1320 +int omap_dss_register_driver(struct omap_dss_driver *);
1321 +void omap_dss_unregister_driver(struct omap_dss_driver *);
1322 +
1323 +int omap_dss_register_device(struct omap_dss_device *);
1324 +void omap_dss_unregister_device(struct omap_dss_device *);
1325 +
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));
1332 +
1333 +int omap_dss_start_device(struct omap_dss_device *dssdev);
1334 +void omap_dss_stop_device(struct omap_dss_device *dssdev);
1335 +
1336 +int omap_dss_get_num_overlay_managers(void);
1337 +struct omap_overlay_manager *omap_dss_get_overlay_manager(int num);
1338 +
1339 +int omap_dss_get_num_overlays(void);
1340 +struct omap_overlay *omap_dss_get_overlay(int num);
1341 +
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);
1345 +
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);
1349 +
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)
1352 +
1353 +#endif
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
1358 +++ /dev/null
1359 @@ -1,398 +0,0 @@
1360 -/*
1361 - * File: arch/arm/plat-omap/include/mach/omapfb.h
1362 - *
1363 - * Framebuffer driver for TI OMAP boards
1364 - *
1365 - * Copyright (C) 2004 Nokia Corporation
1366 - * Author: Imre Deak <imre.deak@nokia.com>
1367 - *
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.
1372 - *
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.
1377 - *
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.
1381 - */
1382 -
1383 -#ifndef __OMAPFB_H
1384 -#define __OMAPFB_H
1385 -
1386 -#include <asm/ioctl.h>
1387 -#include <asm/types.h>
1388 -
1389 -/* IOCTL commands. */
1390 -
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)
1395 -
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)
1412 -
1413 -#define OMAPFB_CAPS_GENERIC_MASK 0x00000fff
1414 -#define OMAPFB_CAPS_LCDC_MASK 0x00fff000
1415 -#define OMAPFB_CAPS_PANEL_MASK 0xff000000
1416 -
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
1426 -
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
1434 -
1435 -#define OMAPFB_EVENT_READY 1
1436 -#define OMAPFB_EVENT_DISABLED 2
1437 -
1438 -#define OMAPFB_MEMTYPE_SDRAM 0
1439 -#define OMAPFB_MEMTYPE_SRAM 1
1440 -#define OMAPFB_MEMTYPE_MAX 1
1441 -
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,
1452 -};
1453 -
1454 -struct omapfb_update_window {
1455 - __u32 x, y;
1456 - __u32 width, height;
1457 - __u32 format;
1458 - __u32 out_x, out_y;
1459 - __u32 out_width, out_height;
1460 - __u32 reserved[8];
1461 -};
1462 -
1463 -struct omapfb_update_window_old {
1464 - __u32 x, y;
1465 - __u32 width, height;
1466 - __u32 format;
1467 -};
1468 -
1469 -enum omapfb_plane {
1470 - OMAPFB_PLANE_GFX = 0,
1471 - OMAPFB_PLANE_VID1,
1472 - OMAPFB_PLANE_VID2,
1473 -};
1474 -
1475 -enum omapfb_channel_out {
1476 - OMAPFB_CHANNEL_OUT_LCD = 0,
1477 - OMAPFB_CHANNEL_OUT_DIGIT,
1478 -};
1479 -
1480 -struct omapfb_plane_info {
1481 - __u32 pos_x;
1482 - __u32 pos_y;
1483 - __u8 enabled;
1484 - __u8 channel_out;
1485 - __u8 mirror;
1486 - __u8 reserved1;
1487 - __u32 out_width;
1488 - __u32 out_height;
1489 - __u32 reserved2[12];
1490 -};
1491 -
1492 -struct omapfb_mem_info {
1493 - __u32 size;
1494 - __u8 type;
1495 - __u8 reserved[3];
1496 -};
1497 -
1498 -struct omapfb_caps {
1499 - __u32 ctrl;
1500 - __u32 plane_color;
1501 - __u32 wnd_color;
1502 -};
1503 -
1504 -enum omapfb_color_key_type {
1505 - OMAPFB_COLOR_KEY_DISABLED = 0,
1506 - OMAPFB_COLOR_KEY_GFX_DST,
1507 - OMAPFB_COLOR_KEY_VID_SRC,
1508 -};
1509 -
1510 -struct omapfb_color_key {
1511 - __u8 channel_out;
1512 - __u32 background;
1513 - __u32 trans_key;
1514 - __u8 key_type;
1515 -};
1516 -
1517 -enum omapfb_update_mode {
1518 - OMAPFB_UPDATE_DISABLED = 0,
1519 - OMAPFB_AUTO_UPDATE,
1520 - OMAPFB_MANUAL_UPDATE
1521 -};
1522 -
1523 -#ifdef __KERNEL__
1524 -
1525 -#include <linux/completion.h>
1526 -#include <linux/interrupt.h>
1527 -#include <linux/fb.h>
1528 -#include <linux/mutex.h>
1529 -
1530 -#include <mach/board.h>
1531 -
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
1538 -
1539 -#define OMAP_LCDC_SIGNAL_MASK 0x003f
1540 -
1541 -#define OMAP_LCDC_PANEL_TFT 0x0100
1542 -
1543 -#define OMAPFB_PLANE_XRES_MIN 8
1544 -#define OMAPFB_PLANE_YRES_MIN 8
1545 -
1546 -#ifdef CONFIG_ARCH_OMAP1
1547 -#define OMAPFB_PLANE_NUM 1
1548 -#else
1549 -#define OMAPFB_PLANE_NUM 3
1550 -#endif
1551 -
1552 -struct omapfb_device;
1553 -
1554 -struct lcd_panel {
1555 - const char *name;
1556 - int config; /* TFT/STN, signal inversion */
1557 - int bpp; /* Pixel format in fb mem */
1558 - int data_lines; /* Lines on LCD HW interface */
1559 -
1560 - int x_res, y_res;
1561 - int pixel_clock; /* In kHz */
1562 - int hsw; /* Horizontal synchronization
1563 - pulse width */
1564 - int hfp; /* Horizontal front porch */
1565 - int hbp; /* Horizontal back porch */
1566 - int vsw; /* Vertical synchronization
1567 - pulse width */
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 */
1573 -
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);
1585 -};
1586 -
1587 -struct extif_timings {
1588 - int cs_on_time;
1589 - int cs_off_time;
1590 - int we_on_time;
1591 - int we_off_time;
1592 - int re_on_time;
1593 - int re_off_time;
1594 - int we_cycle_time;
1595 - int re_cycle_time;
1596 - int cs_pulse_width;
1597 - int access_time;
1598 -
1599 - int clk_div;
1600 -
1601 - u32 tim[5]; /* set by extif->convert_timings */
1602 -
1603 - int converted;
1604 -};
1605 -
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);
1623 -
1624 - unsigned long max_transmit_size;
1625 -};
1626 -
1627 -struct omapfb_notifier_block {
1628 - struct notifier_block nb;
1629 - void *data;
1630 - int plane_idx;
1631 -};
1632 -
1633 -typedef int (*omapfb_notifier_callback_t)(struct notifier_block *,
1634 - unsigned long event,
1635 - void *fbi);
1636 -
1637 -struct omapfb_mem_region {
1638 - u32 paddr;
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 */
1644 -};
1645 -
1646 -struct omapfb_mem_desc {
1647 - int region_cnt;
1648 - struct omapfb_mem_region region[OMAPFB_PLANE_NUM];
1649 -};
1650 -
1651 -struct lcd_ctrl {
1652 - const char *name;
1653 - void *data;
1654 -
1655 - int (*init) (struct omapfb_device *fbdev,
1656 - int ext_mode,
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,
1665 - int screen_width,
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);
1690 -};
1691 -
1692 -enum omapfb_state {
1693 - OMAPFB_DISABLED = 0,
1694 - OMAPFB_SUSPENDED= 99,
1695 - OMAPFB_ACTIVE = 100
1696 -};
1697 -
1698 -struct omapfb_plane_struct {
1699 - int idx;
1700 - struct omapfb_plane_info info;
1701 - enum omapfb_color_format color_mode;
1702 - struct omapfb_device *fbdev;
1703 -};
1704 -
1705 -struct omapfb_device {
1706 - int state;
1707 - int ext_lcdc; /* Using external
1708 - LCD controller */
1709 - struct mutex rqueue_mutex;
1710 -
1711 - int palette_size;
1712 - u32 pseudo_palette[17];
1713 -
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
1718 - interface */
1719 - struct device *dev;
1720 - struct fb_var_screeninfo new_var; /* for mode changes */
1721 -
1722 - struct omapfb_mem_desc mem_desc;
1723 - struct fb_info *fb_info[OMAPFB_PLANE_NUM];
1724 -};
1725 -
1726 -struct omapfb_platform_data {
1727 - struct omap_lcd_config lcd;
1728 - struct omapfb_mem_desc mem_desc;
1729 - void *ctrl_platform_data;
1730 -};
1731 -
1732 -#ifdef CONFIG_ARCH_OMAP1
1733 -extern struct lcd_ctrl omap1_lcd_ctrl;
1734 -#else
1735 -extern struct lcd_ctrl omap2_disp_ctrl;
1736 -#endif
1737 -
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);
1751 -
1752 -/* in arch/arm/plat-omap/fb.c */
1753 -extern void omapfb_set_ctrl_platform_data(void *pdata);
1754 -
1755 -#endif /* __KERNEL__ */
1756 -
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
1762 @@ -88,7 +88,10 @@
1763
1764 /* SMS register offsets - read/write with sms_{read,write}_reg() */
1765
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 */
1772
1773
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);
1777
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);
1781 +
1782 #ifdef CONFIG_ARCH_OMAP2
1783
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
1788 --- /dev/null
1789 +++ b/arch/arm/plat-omap/include/mach/vram.h
1790 @@ -0,0 +1,63 @@
1791 +/*
1792 + * VRAM manager for OMAP
1793 + *
1794 + * Copyright (C) 2009 Nokia Corporation
1795 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
1796 + *
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.
1800 + *
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.
1805 + *
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.
1809 + */
1810 +
1811 +#ifndef __OMAP_VRAM_H__
1812 +#define __OMAP_VRAM_H__
1813 +
1814 +#include <linux/autoconf.h>
1815 +#include <linux/types.h>
1816 +
1817 +#define OMAP_VRAM_MEMTYPE_SDRAM 0
1818 +#define OMAP_VRAM_MEMTYPE_SRAM 1
1819 +#define OMAP_VRAM_MEMTYPE_MAX 1
1820 +
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);
1827 +
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);
1831 +
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);
1838 +#else
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) { }
1841 +
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)
1848 +{
1849 + return 0;
1850 +}
1851 +#endif
1852 +
1853 +#endif
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
1857 --- /dev/null
1858 +++ b/arch/arm/plat-omap/include/mach/vrfb.h
1859 @@ -0,0 +1,46 @@
1860 +/*
1861 + * VRFB Rotation Engine
1862 + *
1863 + * Copyright (C) 2009 Nokia Corporation
1864 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
1865 + *
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.
1869 + *
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.
1874 + *
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.
1878 + */
1879 +
1880 +#ifndef __OMAP_VRFB_H__
1881 +#define __OMAP_VRFB_H__
1882 +
1883 +#define OMAP_VRFB_LINE_LEN 2048
1884 +
1885 +struct vrfb {
1886 + u8 context;
1887 + void __iomem *vaddr[4];
1888 + unsigned long paddr[4];
1889 + u16 xoffset;
1890 + u16 yoffset;
1891 + u8 bytespp;
1892 +};
1893 +
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,
1899 + u8 bytespp);
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);
1904 +
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
1910 @@ -28,6 +28,7 @@
1911 #include <mach/sram.h>
1912 #include <mach/board.h>
1913 #include <mach/cpu.h>
1914 +#include <mach/vram.h>
1915
1916 #include <mach/control.h>
1917
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;
1922 +
1923 + reserved = omap_vram_reserve_sram(omap_sram_start, omap_sram_base,
1924 + omap_sram_size,
1925 + omap_sram_start + SRAM_BOOTLOADER_SZ,
1926 + omap_sram_size - SRAM_BOOTLOADER_SZ);
1927 + omap_sram_size -= reserved;
1928 +
1929 omap_sram_ceil = omap_sram_base + omap_sram_size;
1930 }
1931
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
1937 a bridge adapter.
1938
1939 source "drivers/video/omap/Kconfig"
1940 +source "drivers/video/omap2/Kconfig"
1941
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/
1952 +obj-y += omap2/
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
1960 @@ -1,6 +1,7 @@
1961 config FB_OMAP
1962 tristate "OMAP frame buffer support (EXPERIMENTAL)"
1963 - depends on FB && ARCH_OMAP
1964 + depends on FB && ARCH_OMAP && (OMAP2_DSS = "n")
1965 +
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
1970
1971 config FB_OMAP_BOOTLOADER_INIT
1972 bool "Check bootloader initialization"
1973 - depends on FB_OMAP
1974 + depends on FB_OMAP || FB_OMAP2
1975 help
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
1982 @@ -27,9 +27,9 @@
1983 #include <linux/clk.h>
1984
1985 #include <mach/dma.h>
1986 -#include <mach/omapfb.h>
1987 #include <mach/blizzard.h>
1988
1989 +#include "omapfb.h"
1990 #include "dispc.h"
1991
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
1997 @@ -24,11 +24,12 @@
1998 #include <linux/vmalloc.h>
1999 #include <linux/clk.h>
2000 #include <linux/io.h>
2001 +#include <linux/platform_device.h>
2002
2003 #include <mach/sram.h>
2004 -#include <mach/omapfb.h>
2005 #include <mach/board.h>
2006
2007 +#include "omapfb.h"
2008 #include "dispc.h"
2009
2010 #define MODULE_NAME "dispc"
2011 @@ -188,6 +189,11 @@ static struct {
2012 struct omapfb_color_key color_key;
2013 } dispc;
2014
2015 +static struct platform_device omapdss_device = {
2016 + .name = "omapdss",
2017 + .id = -1,
2018 +};
2019 +
2020 static void enable_lcd_clocks(int enable);
2021
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)
2024
2025 static int get_dss_clocks(void)
2026 {
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);
2032 }
2033
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);
2040 }
2041
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,
2048 int skip_init = 0;
2049 int i;
2050
2051 + r = platform_device_register(&omapdss_device);
2052 + if (r) {
2053 + dev_err(fbdev->dev, "can't register omapdss device\n");
2054 + return r;
2055 + }
2056 +
2057 memset(&dispc, 0, sizeof(dispc));
2058
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);
2062 put_dss_clocks();
2063 iounmap(dispc.base);
2064 + platform_device_unregister(&omapdss_device);
2065 }
2066
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
2072 @@ -27,8 +27,8 @@
2073 #include <linux/clk.h>
2074
2075 #include <mach/dma.h>
2076 -#include <mach/omapfb.h>
2077 #include <mach/hwa742.h>
2078 +#include "omapfb.h"
2079
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
2086 @@ -28,9 +28,10 @@
2087 #include <linux/i2c/twl4030.h>
2088
2089 #include <mach/mux.h>
2090 -#include <mach/omapfb.h>
2091 #include <asm/mach-types.h>
2092
2093 +#include "omapfb.h"
2094 +
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
2102 @@ -27,7 +27,8 @@
2103
2104 #include <mach/board-ams-delta.h>
2105 #include <mach/hardware.h>
2106 -#include <mach/omapfb.h>
2107 +
2108 +#include "omapfb.h"
2109
2110 #define AMS_DELTA_DEFAULT_CONTRAST 112
2111
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
2116 @@ -26,7 +26,8 @@
2117
2118 #include <mach/gpio.h>
2119 #include <mach/mux.h>
2120 -#include <mach/omapfb.h>
2121 +
2122 +#include "omapfb.h"
2123
2124 /* #define USE_35INCH_LCD 1 */
2125
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
2130 @@ -24,7 +24,7 @@
2131 #include <linux/i2c/tps65010.h>
2132
2133 #include <mach/gpio.h>
2134 -#include <mach/omapfb.h>
2135 +#include "omapfb.h"
2136
2137 #define MODULE_NAME "omapfb-lcd_h3"
2138
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
2143 @@ -22,7 +22,7 @@
2144 #include <linux/module.h>
2145 #include <linux/platform_device.h>
2146
2147 -#include <mach/omapfb.h>
2148 +#include "omapfb.h"
2149
2150 static int h4_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
2151 {
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
2156 @@ -24,7 +24,7 @@
2157 #include <linux/io.h>
2158
2159 #include <mach/fpga.h>
2160 -#include <mach/omapfb.h>
2161 +#include "omapfb.h"
2162
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
2169 @@ -23,7 +23,7 @@
2170 #include <linux/platform_device.h>
2171
2172 #include <mach/gpio.h>
2173 -#include <mach/omapfb.h>
2174 +#include "omapfb.h"
2175
2176 #define MODULE_NAME "omapfb-lcd_h3"
2177
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
2182 @@ -28,9 +28,10 @@
2183
2184 #include <mach/gpio.h>
2185 #include <mach/mux.h>
2186 -#include <mach/omapfb.h>
2187 #include <asm/mach-types.h>
2188
2189 +#include "omapfb.h"
2190 +
2191 #define LCD_PANEL_BACKLIGHT_GPIO (15 + OMAP_MAX_GPIO_LINES)
2192 #define LCD_PANEL_ENABLE_GPIO (7 + OMAP_MAX_GPIO_LINES)
2193
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
2198 @@ -23,9 +23,10 @@
2199 #include <linux/workqueue.h>
2200 #include <linux/spi/spi.h>
2201
2202 -#include <mach/omapfb.h>
2203 #include <mach/lcd_mipid.h>
2204
2205 +#include "omapfb.h"
2206 +
2207 #define MIPID_MODULE_NAME "lcd_mipid"
2208
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
2214 @@ -27,9 +27,10 @@
2215 #include <linux/i2c/twl4030.h>
2216
2217 #include <mach/mux.h>
2218 -#include <mach/omapfb.h>
2219 #include <asm/mach-types.h>
2220
2221 +#include "omapfb.h"
2222 +
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
2230 @@ -26,9 +26,10 @@
2231 #include <linux/i2c/twl4030.h>
2232
2233 #include <mach/mux.h>
2234 -#include <mach/omapfb.h>
2235 #include <asm/mach-types.h>
2236
2237 +#include "omapfb.h"
2238 +
2239 #define LCD_PANEL_ENABLE_GPIO 170
2240
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
2246 @@ -26,9 +26,10 @@
2247 #include <linux/i2c/twl4030.h>
2248
2249 #include <mach/mux.h>
2250 -#include <mach/omapfb.h>
2251 #include <asm/mach-types.h>
2252
2253 +#include "omapfb.h"
2254 +
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
2262 @@ -25,7 +25,7 @@
2263
2264 #include <mach/gpio.h>
2265 #include <mach/mux.h>
2266 -#include <mach/omapfb.h>
2267 +#include "omapfb.h"
2268
2269 static int osk_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
2270 {
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
2275 @@ -25,9 +25,10 @@
2276
2277 #include <mach/gpio.h>
2278 #include <mach/mux.h>
2279 -#include <mach/omapfb.h>
2280 #include <asm/mach-types.h>
2281
2282 +#include "omapfb.h"
2283 +
2284 #define LCD_ENABLE 144
2285
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
2291 @@ -24,7 +24,7 @@
2292 #include <linux/io.h>
2293
2294 #include <mach/fpga.h>
2295 -#include <mach/omapfb.h>
2296 +#include "omapfb.h"
2297
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>
2306
2307 #include <mach/gpio.h>
2308 -#include <mach/omapfb.h>
2309 +#include "omapfb.h"
2310
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
2317 @@ -24,7 +24,7 @@
2318 #include <linux/platform_device.h>
2319 #include <linux/io.h>
2320
2321 -#include <mach/omapfb.h>
2322 +#include "omapfb.h"
2323
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
2330 @@ -30,10 +30,11 @@
2331 #include <linux/clk.h>
2332
2333 #include <mach/dma.h>
2334 -#include <mach/omapfb.h>
2335
2336 #include <asm/mach-types.h>
2337
2338 +#include "omapfb.h"
2339 +
2340 #include "lcdc.h"
2341
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
2346 --- /dev/null
2347 +++ b/drivers/video/omap/omapfb.h
2348 @@ -0,0 +1,227 @@
2349 +/*
2350 + * File: drivers/video/omap/omapfb.h
2351 + *
2352 + * Framebuffer driver for TI OMAP boards
2353 + *
2354 + * Copyright (C) 2004 Nokia Corporation
2355 + * Author: Imre Deak <imre.deak@nokia.com>
2356 + *
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.
2361 + *
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.
2366 + *
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.
2370 + */
2371 +
2372 +#ifndef __OMAPFB_H
2373 +#define __OMAPFB_H
2374 +
2375 +#include <linux/fb.h>
2376 +#include <linux/mutex.h>
2377 +#include <linux/omapfb.h>
2378 +
2379 +#define OMAPFB_EVENT_READY 1
2380 +#define OMAPFB_EVENT_DISABLED 2
2381 +
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
2388 +
2389 +#define OMAP_LCDC_SIGNAL_MASK 0x003f
2390 +
2391 +#define OMAP_LCDC_PANEL_TFT 0x0100
2392 +
2393 +#define OMAPFB_PLANE_XRES_MIN 8
2394 +#define OMAPFB_PLANE_YRES_MIN 8
2395 +
2396 +struct omapfb_device;
2397 +
2398 +struct lcd_panel {
2399 + const char *name;
2400 + int config; /* TFT/STN, signal inversion */
2401 + int bpp; /* Pixel format in fb mem */
2402 + int data_lines; /* Lines on LCD HW interface */
2403 +
2404 + int x_res, y_res;
2405 + int pixel_clock; /* In kHz */
2406 + int hsw; /* Horizontal synchronization
2407 + pulse width */
2408 + int hfp; /* Horizontal front porch */
2409 + int hbp; /* Horizontal back porch */
2410 + int vsw; /* Vertical synchronization
2411 + pulse width */
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 */
2417 +
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);
2429 +};
2430 +
2431 +struct extif_timings {
2432 + int cs_on_time;
2433 + int cs_off_time;
2434 + int we_on_time;
2435 + int we_off_time;
2436 + int re_on_time;
2437 + int re_off_time;
2438 + int we_cycle_time;
2439 + int re_cycle_time;
2440 + int cs_pulse_width;
2441 + int access_time;
2442 +
2443 + int clk_div;
2444 +
2445 + u32 tim[5]; /* set by extif->convert_timings */
2446 +
2447 + int converted;
2448 +};
2449 +
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);
2467 +
2468 + unsigned long max_transmit_size;
2469 +};
2470 +
2471 +struct omapfb_notifier_block {
2472 + struct notifier_block nb;
2473 + void *data;
2474 + int plane_idx;
2475 +};
2476 +
2477 +typedef int (*omapfb_notifier_callback_t)(struct notifier_block *,
2478 + unsigned long event,
2479 + void *fbi);
2480 +
2481 +struct lcd_ctrl {
2482 + const char *name;
2483 + void *data;
2484 +
2485 + int (*init) (struct omapfb_device *fbdev,
2486 + int ext_mode,
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,
2495 + int screen_width,
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);
2520 +};
2521 +
2522 +enum omapfb_state {
2523 + OMAPFB_DISABLED = 0,
2524 + OMAPFB_SUSPENDED = 99,
2525 + OMAPFB_ACTIVE = 100
2526 +};
2527 +
2528 +struct omapfb_plane_struct {
2529 + int idx;
2530 + struct omapfb_plane_info info;
2531 + enum omapfb_color_format color_mode;
2532 + struct omapfb_device *fbdev;
2533 +};
2534 +
2535 +struct omapfb_device {
2536 + int state;
2537 + int ext_lcdc; /* Using external
2538 + LCD controller */
2539 + struct mutex rqueue_mutex;
2540 +
2541 + int palette_size;
2542 + u32 pseudo_palette[17];
2543 +
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
2548 + interface */
2549 + struct device *dev;
2550 + struct fb_var_screeninfo new_var; /* for mode changes */
2551 +
2552 + struct omapfb_mem_desc mem_desc;
2553 + struct fb_info *fb_info[OMAPFB_PLANE_NUM];
2554 +};
2555 +
2556 +#ifdef CONFIG_ARCH_OMAP1
2557 +extern struct lcd_ctrl omap1_lcd_ctrl;
2558 +#else
2559 +extern struct lcd_ctrl omap2_disp_ctrl;
2560 +#endif
2561 +
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);
2574 +
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
2580 @@ -29,8 +29,8 @@
2581 #include <linux/uaccess.h>
2582
2583 #include <mach/dma.h>
2584 -#include <mach/omapfb.h>
2585
2586 +#include "omapfb.h"
2587 #include "lcdc.h"
2588 #include "dispc.h"
2589
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
2594 @@ -27,8 +27,7 @@
2595 #include <linux/clk.h>
2596 #include <linux/io.h>
2597
2598 -#include <mach/omapfb.h>
2599 -
2600 +#include "omapfb.h"
2601 #include "dispc.h"
2602
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
2608 @@ -25,8 +25,8 @@
2609 #include <linux/io.h>
2610
2611 #include <mach/dma.h>
2612 -#include <mach/omapfb.h>
2613
2614 +#include "omapfb.h"
2615 #include "lcdc.h"
2616
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
2621 --- /dev/null
2622 +++ b/drivers/video/omap2/Kconfig
2623 @@ -0,0 +1,9 @@
2624 +config OMAP2_VRAM
2625 + bool
2626 +
2627 +config OMAP2_VRFB
2628 + bool
2629 +
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
2636 --- /dev/null
2637 +++ b/drivers/video/omap2/Makefile
2638 @@ -0,0 +1,6 @@
2639 +obj-$(CONFIG_OMAP2_VRAM) += vram.o
2640 +obj-$(CONFIG_OMAP2_VRFB) += vrfb.o
2641 +
2642 +obj-y += dss/
2643 +obj-y += omapfb/
2644 +obj-y += displays/
2645 diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig
2646 new file mode 100644
2647 index 0000000..79d2861
2648 --- /dev/null
2649 +++ b/drivers/video/omap2/displays/Kconfig
2650 @@ -0,0 +1,28 @@
2651 +menu "OMAP2/3 Display Device Drivers"
2652 + depends on OMAP2_DSS
2653 +
2654 +config PANEL_GENERIC
2655 + tristate "Generic Panel"
2656 + help
2657 + Generic panel driver.
2658 + Used for DVI output for Beagle and OMAP3 SDP.
2659 +
2660 +config PANEL_SAMSUNG_LTE430WQ_F0C
2661 + tristate "Samsung LTE430WQ-F0C LCD Panel"
2662 + depends on OMAP2_DSS
2663 + help
2664 + LCD Panel used on Overo Palo43
2665 +
2666 +config PANEL_SHARP_LS037V7DW01
2667 + tristate "Sharp LS037V7DW01 LCD Panel"
2668 + depends on OMAP2_DSS
2669 + help
2670 + LCD Panel used in TI's SDP3430 and EVM boards
2671 +
2672 +config PANEL_TAAL
2673 + tristate "Taal DSI Panel"
2674 + depends on OMAP2_DSS_DSI
2675 + help
2676 + Taal DSI command mode panel from TPO.
2677 +
2678 +endmenu
2679 diff --git a/drivers/video/omap2/displays/Makefile b/drivers/video/omap2/displays/Makefile
2680 new file mode 100644
2681 index 0000000..d44e765
2682 --- /dev/null
2683 +++ b/drivers/video/omap2/displays/Makefile
2684 @@ -0,0 +1,5 @@
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
2688 +
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
2693 --- /dev/null
2694 +++ b/drivers/video/omap2/displays/panel-generic.c
2695 @@ -0,0 +1,104 @@
2696 +/*
2697 + * Generic panel support
2698 + *
2699 + * Copyright (C) 2008 Nokia Corporation
2700 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
2701 + *
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.
2705 + *
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
2709 + * more details.
2710 + *
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/>.
2713 + */
2714 +
2715 +#include <linux/module.h>
2716 +#include <linux/delay.h>
2717 +
2718 +#include <mach/display.h>
2719 +
2720 +static struct omap_video_timings generic_panel_timings = {
2721 + /* 640 x 480 @ 60 Hz Reduced blanking VESA CVT 0.31M3-R */
2722 + .x_res = 640,
2723 + .y_res = 480,
2724 + .pixel_clock = 23500,
2725 + .hfp = 48,
2726 + .hsw = 32,
2727 + .hbp = 80,
2728 + .vfp = 3,
2729 + .vsw = 4,
2730 + .vbp = 7,
2731 +};
2732 +
2733 +static int generic_panel_probe(struct omap_dss_device *dssdev)
2734 +{
2735 + dssdev->panel.config = OMAP_DSS_LCD_TFT;
2736 + dssdev->panel.timings = generic_panel_timings;
2737 +
2738 + return 0;
2739 +}
2740 +
2741 +static void generic_panel_remove(struct omap_dss_device *dssdev)
2742 +{
2743 +}
2744 +
2745 +static int generic_panel_enable(struct omap_dss_device *dssdev)
2746 +{
2747 + int r = 0;
2748 +
2749 + if (dssdev->platform_enable)
2750 + r = dssdev->platform_enable(dssdev);
2751 +
2752 + return r;
2753 +}
2754 +
2755 +static void generic_panel_disable(struct omap_dss_device *dssdev)
2756 +{
2757 + if (dssdev->platform_disable)
2758 + dssdev->platform_disable(dssdev);
2759 +}
2760 +
2761 +static int generic_panel_suspend(struct omap_dss_device *dssdev)
2762 +{
2763 + generic_panel_disable(dssdev);
2764 + return 0;
2765 +}
2766 +
2767 +static int generic_panel_resume(struct omap_dss_device *dssdev)
2768 +{
2769 + return generic_panel_enable(dssdev);
2770 +}
2771 +
2772 +static struct omap_dss_driver generic_driver = {
2773 + .probe = generic_panel_probe,
2774 + .remove = generic_panel_remove,
2775 +
2776 + .enable = generic_panel_enable,
2777 + .disable = generic_panel_disable,
2778 + .suspend = generic_panel_suspend,
2779 + .resume = generic_panel_resume,
2780 +
2781 + .driver = {
2782 + .name = "generic_panel",
2783 + .owner = THIS_MODULE,
2784 + },
2785 +};
2786 +
2787 +static int __init generic_panel_drv_init(void)
2788 +{
2789 + return omap_dss_register_driver(&generic_driver);
2790 +}
2791 +
2792 +static void __exit generic_panel_drv_exit(void)
2793 +{
2794 + omap_dss_unregister_driver(&generic_driver);
2795 +}
2796 +
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
2803 --- /dev/null
2804 +++ b/drivers/video/omap2/displays/panel-samsung-lte430wq-f0c.c
2805 @@ -0,0 +1,113 @@
2806 +/*
2807 + * LCD panel driver for Samsung LTE430WQ-F0C
2808 + *
2809 + * Author: Steve Sakoman <steve@sakoman.com>
2810 + *
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.
2814 + *
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
2818 + * more details.
2819 + *
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/>.
2822 + */
2823 +
2824 +#include <linux/module.h>
2825 +#include <linux/delay.h>
2826 +
2827 +#include <mach/display.h>
2828 +
2829 +static struct omap_video_timings samsung_lte_timings = {
2830 + .x_res = 480,
2831 + .y_res = 272,
2832 +
2833 + .pixel_clock = 9200,
2834 +
2835 + .hsw = 41,
2836 + .hfp = 8,
2837 + .hbp = 45-41,
2838 +
2839 + .vsw = 10,
2840 + .vfp = 4,
2841 + .vbp = 12-10,
2842 +};
2843 +
2844 +static int samsung_lte_panel_probe(struct omap_dss_device *dssdev)
2845 +{
2846 + dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
2847 + OMAP_DSS_LCD_IHS;
2848 + dssdev->panel.timings = samsung_lte_timings;
2849 +
2850 + return 0;
2851 +}
2852 +
2853 +static void samsung_lte_panel_remove(struct omap_dss_device *dssdev)
2854 +{
2855 +}
2856 +
2857 +static int samsung_lte_panel_enable(struct omap_dss_device *dssdev)
2858 +{
2859 + int r = 0;
2860 +
2861 + /* wait couple of vsyncs until enabling the LCD */
2862 + msleep(50);
2863 +
2864 + if (dssdev->platform_enable)
2865 + r = dssdev->platform_enable(dssdev);
2866 +
2867 + return r;
2868 +}
2869 +
2870 +static void samsung_lte_panel_disable(struct omap_dss_device *dssdev)
2871 +{
2872 + if (dssdev->platform_disable)
2873 + dssdev->platform_disable(dssdev);
2874 +
2875 + /* wait at least 5 vsyncs after disabling the LCD */
2876 +
2877 + msleep(100);
2878 +}
2879 +
2880 +static int samsung_lte_panel_suspend(struct omap_dss_device *dssdev)
2881 +{
2882 + samsung_lte_panel_disable(dssdev);
2883 + return 0;
2884 +}
2885 +
2886 +static int samsung_lte_panel_resume(struct omap_dss_device *dssdev)
2887 +{
2888 + return samsung_lte_panel_enable(dssdev);
2889 +}
2890 +
2891 +static struct omap_dss_driver samsung_lte_driver = {
2892 + .probe = samsung_lte_panel_probe,
2893 + .remove = samsung_lte_panel_remove,
2894 +
2895 + .enable = samsung_lte_panel_enable,
2896 + .disable = samsung_lte_panel_disable,
2897 + .suspend = samsung_lte_panel_suspend,
2898 + .resume = samsung_lte_panel_resume,
2899 +
2900 + .driver = {
2901 + .name = "samsung_lte_panel",
2902 + .owner = THIS_MODULE,
2903 + },
2904 +};
2905 +
2906 +static int __init samsung_lte_panel_drv_init(void)
2907 +{
2908 + return omap_dss_register_driver(&samsung_lte_driver);
2909 +}
2910 +
2911 +static void __exit samsung_lte_panel_drv_exit(void)
2912 +{
2913 + omap_dss_unregister_driver(&samsung_lte_driver);
2914 +}
2915 +
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
2922 --- /dev/null
2923 +++ b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c
2924 @@ -0,0 +1,153 @@
2925 +/*
2926 + * LCD panel driver for Sharp LS037V7DW01
2927 + *
2928 + * Copyright (C) 2008 Nokia Corporation
2929 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
2930 + *
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.
2934 + *
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
2938 + * more details.
2939 + *
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/>.
2942 + */
2943 +
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>
2949 +
2950 +#include <mach/display.h>
2951 +
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;
2958 +};
2959 +
2960 +static struct omap_video_timings sharp_ls_timings = {
2961 + .x_res = 480,
2962 + .y_res = 640,
2963 +
2964 + .pixel_clock = 19200,
2965 +
2966 + .hsw = 2,
2967 + .hfp = 1,
2968 + .hbp = 28,
2969 +
2970 + .vsw = 1,
2971 + .vfp = 1,
2972 + .vbp = 1,
2973 +};
2974 +
2975 +static int sharp_ls_panel_probe(struct omap_dss_device *dssdev)
2976 +{
2977 + struct sharp_data *sd;
2978 +
2979 + dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
2980 + OMAP_DSS_LCD_IHS;
2981 + dssdev->panel.acb = 0x28;
2982 + dssdev->panel.timings = sharp_ls_timings;
2983 +
2984 + sd = kzalloc(sizeof(*sd), GFP_KERNEL);
2985 + if (!sd)
2986 + return -ENOMEM;
2987 +
2988 + dev_set_drvdata(&dssdev->dev, sd);
2989 +
2990 + sd->vdvi_reg = regulator_get(&dssdev->dev, "vdvi");
2991 + if (IS_ERR(sd->vdvi_reg)) {
2992 + kfree(sd);
2993 + pr_err("failed to get VDVI regulator\n");
2994 + return PTR_ERR(sd->vdvi_reg);
2995 + }
2996 +
2997 + return 0;
2998 +}
2999 +
3000 +static void sharp_ls_panel_remove(struct omap_dss_device *dssdev)
3001 +{
3002 + struct sharp_data *sd = dev_get_drvdata(&dssdev->dev);
3003 +
3004 + regulator_put(sd->vdvi_reg);
3005 +
3006 + kfree(sd);
3007 +}
3008 +
3009 +static int sharp_ls_panel_enable(struct omap_dss_device *dssdev)
3010 +{
3011 + struct sharp_data *sd = dev_get_drvdata(&dssdev->dev);
3012 + int r = 0;
3013 +
3014 + /* wait couple of vsyncs until enabling the LCD */
3015 + msleep(50);
3016 +
3017 + regulator_enable(sd->vdvi_reg);
3018 +
3019 + if (dssdev->platform_enable)
3020 + r = dssdev->platform_enable(dssdev);
3021 +
3022 + return r;
3023 +}
3024 +
3025 +static void sharp_ls_panel_disable(struct omap_dss_device *dssdev)
3026 +{
3027 + struct sharp_data *sd = dev_get_drvdata(&dssdev->dev);
3028 +
3029 + if (dssdev->platform_disable)
3030 + dssdev->platform_disable(dssdev);
3031 +
3032 + regulator_disable(sd->vdvi_reg);
3033 +
3034 + /* wait at least 5 vsyncs after disabling the LCD */
3035 +
3036 + msleep(100);
3037 +}
3038 +
3039 +static int sharp_ls_panel_suspend(struct omap_dss_device *dssdev)
3040 +{
3041 + sharp_ls_panel_disable(dssdev);
3042 + return 0;
3043 +}
3044 +
3045 +static int sharp_ls_panel_resume(struct omap_dss_device *dssdev)
3046 +{
3047 + return sharp_ls_panel_enable(dssdev);
3048 +}
3049 +
3050 +static struct omap_dss_driver sharp_ls_driver = {
3051 + .probe = sharp_ls_panel_probe,
3052 + .remove = sharp_ls_panel_remove,
3053 +
3054 + .enable = sharp_ls_panel_enable,
3055 + .disable = sharp_ls_panel_disable,
3056 + .suspend = sharp_ls_panel_suspend,
3057 + .resume = sharp_ls_panel_resume,
3058 +
3059 + .driver = {
3060 + .name = "sharp_ls_panel",
3061 + .owner = THIS_MODULE,
3062 + },
3063 +};
3064 +
3065 +static int __init sharp_ls_panel_drv_init(void)
3066 +{
3067 + return omap_dss_register_driver(&sharp_ls_driver);
3068 +}
3069 +
3070 +static void __exit sharp_ls_panel_drv_exit(void)
3071 +{
3072 + omap_dss_unregister_driver(&sharp_ls_driver);
3073 +}
3074 +
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
3081 --- /dev/null
3082 +++ b/drivers/video/omap2/displays/panel-taal.c
3083 @@ -0,0 +1,900 @@
3084 +/*
3085 + * Taal DSI command mode panel
3086 + *
3087 + * Copyright (C) 2009 Nokia Corporation
3088 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
3089 + *
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.
3093 + *
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
3097 + * more details.
3098 + *
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/>.
3101 + */
3102 +
3103 +/*#define DEBUG*/
3104 +
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>
3115 +
3116 +#include <mach/display.h>
3117 +
3118 +/* DSI Virtual channel. Hardcoded for now. */
3119 +#define TCH 0
3120 +
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
3143 +
3144 +struct taal_data {
3145 + struct backlight_device *bldev;
3146 +
3147 + unsigned long hw_guard_end; /* next value of jiffies when we can
3148 + * issue the next sleep in/out command
3149 + */
3150 + unsigned long hw_guard_wait; /* max guard time in jiffies */
3151 +
3152 + struct omap_dss_device *dssdev;
3153 +
3154 + bool enabled;
3155 + u8 rotate;
3156 + bool mirror;
3157 +
3158 + bool te_enabled;
3159 + bool use_ext_te;
3160 + struct completion te_completion;
3161 +
3162 + bool use_dsi_bl;
3163 +
3164 + bool cabc_broken;
3165 + unsigned cabc_mode;
3166 +
3167 + bool intro_printed;
3168 +};
3169 +
3170 +static void hw_guard_start(struct taal_data *td, int guard_msec)
3171 +{
3172 + td->hw_guard_wait = msecs_to_jiffies(guard_msec);
3173 + td->hw_guard_end = jiffies + td->hw_guard_wait;
3174 +}
3175 +
3176 +static void hw_guard_wait(struct taal_data *td)
3177 +{
3178 + unsigned long wait = td->hw_guard_end - jiffies;
3179 +
3180 + if ((long)wait > 0 && wait <= td->hw_guard_wait) {
3181 + set_current_state(TASK_UNINTERRUPTIBLE);
3182 + schedule_timeout(wait);
3183 + }
3184 +}
3185 +
3186 +static int taal_dcs_read_1(u8 dcs_cmd, u8 *data)
3187 +{
3188 + int r;
3189 + u8 buf[1];
3190 +
3191 + r = dsi_vc_dcs_read(TCH, dcs_cmd, buf, 1);
3192 +
3193 + if (r < 0)
3194 + return r;
3195 +
3196 + *data = buf[0];
3197 +
3198 + return 0;
3199 +}
3200 +
3201 +static int taal_dcs_write_0(u8 dcs_cmd)
3202 +{
3203 + return dsi_vc_dcs_write(TCH, &dcs_cmd, 1);
3204 +}
3205 +
3206 +static int taal_dcs_write_1(u8 dcs_cmd, u8 param)
3207 +{
3208 + u8 buf[2];
3209 + buf[0] = dcs_cmd;
3210 + buf[1] = param;
3211 + return dsi_vc_dcs_write(TCH, buf, 2);
3212 +}
3213 +
3214 +static int taal_sleep_in(struct taal_data *td)
3215 +
3216 +{
3217 + u8 cmd;
3218 + int r;
3219 +
3220 + hw_guard_wait(td);
3221 +
3222 + cmd = DCS_SLEEP_IN;
3223 + r = dsi_vc_dcs_write_nosync(TCH, &cmd, 1);
3224 + if (r)
3225 + return r;
3226 +
3227 + hw_guard_start(td, 120);
3228 +
3229 + msleep(5);
3230 +
3231 + return 0;
3232 +}
3233 +
3234 +static int taal_sleep_out(struct taal_data *td)
3235 +{
3236 + int r;
3237 +
3238 + hw_guard_wait(td);
3239 +
3240 + r = taal_dcs_write_0(DCS_SLEEP_OUT);
3241 + if (r)
3242 + return r;
3243 +
3244 + hw_guard_start(td, 120);
3245 +
3246 + msleep(5);
3247 +
3248 + return 0;
3249 +}
3250 +
3251 +static int taal_get_id(u8 *id1, u8 *id2, u8 *id3)
3252 +{
3253 + int r;
3254 +
3255 + r = taal_dcs_read_1(DCS_GET_ID1, id1);
3256 + if (r)
3257 + return r;
3258 + r = taal_dcs_read_1(DCS_GET_ID2, id2);
3259 + if (r)
3260 + return r;
3261 + r = taal_dcs_read_1(DCS_GET_ID3, id3);
3262 + if (r)
3263 + return r;
3264 +
3265 + return 0;
3266 +}
3267 +
3268 +static int taal_set_addr_mode(u8 rotate, bool mirror)
3269 +{
3270 + int r;
3271 + u8 mode;
3272 + int b5, b6, b7;
3273 +
3274 + r = taal_dcs_read_1(DCS_READ_MADCTL, &mode);
3275 + if (r)
3276 + return r;
3277 +
3278 + switch (rotate) {
3279 + default:
3280 + case 0:
3281 + b7 = 0;
3282 + b6 = 0;
3283 + b5 = 0;
3284 + break;
3285 + case 1:
3286 + b7 = 0;
3287 + b6 = 1;
3288 + b5 = 1;
3289 + break;
3290 + case 2:
3291 + b7 = 1;
3292 + b6 = 1;
3293 + b5 = 0;
3294 + break;
3295 + case 3:
3296 + b7 = 1;
3297 + b6 = 0;
3298 + b5 = 1;
3299 + break;
3300 + }
3301 +
3302 + if (mirror)
3303 + b6 = !b6;
3304 +
3305 + mode &= ~((1<<7) | (1<<6) | (1<<5));
3306 + mode |= (b7 << 7) | (b6 << 6) | (b5 << 5);
3307 +
3308 + return taal_dcs_write_1(DCS_MEM_ACC_CTRL, mode);
3309 +}
3310 +
3311 +static int taal_set_update_window(u16 x, u16 y, u16 w, u16 h)
3312 +{
3313 + int r;
3314 + u16 x1 = x;
3315 + u16 x2 = x + w - 1;
3316 + u16 y1 = y;
3317 + u16 y2 = y + h - 1;
3318 +
3319 + u8 buf[5];
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;
3325 +
3326 + r = dsi_vc_dcs_write_nosync(TCH, buf, sizeof(buf));
3327 + if (r)
3328 + return r;
3329 +
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;
3335 +
3336 + r = dsi_vc_dcs_write_nosync(TCH, buf, sizeof(buf));
3337 + if (r)
3338 + return r;
3339 +
3340 + dsi_vc_send_bta_sync(TCH);
3341 +
3342 + return r;
3343 +}
3344 +
3345 +static int taal_bl_update_status(struct backlight_device *dev)
3346 +{
3347 + struct omap_dss_device *dssdev = dev_get_drvdata(&dev->dev);
3348 + struct taal_data *td = dev_get_drvdata(&dssdev->dev);
3349 + int r;
3350 + int level;
3351 +
3352 + if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
3353 + dev->props.power == FB_BLANK_UNBLANK)
3354 + level = dev->props.brightness;
3355 + else
3356 + level = 0;
3357 +
3358 + dev_dbg(&dssdev->dev, "update brightness to %d\n", level);
3359 +
3360 + if (td->use_dsi_bl) {
3361 + if (td->enabled) {
3362 + dsi_bus_lock();
3363 + r = taal_dcs_write_1(DCS_BRIGHTNESS, level);
3364 + dsi_bus_unlock();
3365 + if (r)
3366 + return r;
3367 + }
3368 + } else {
3369 + if (!dssdev->set_backlight)
3370 + return -EINVAL;
3371 +
3372 + r = dssdev->set_backlight(dssdev, level);
3373 + if (r)
3374 + return r;
3375 + }
3376 +
3377 + return 0;
3378 +}
3379 +
3380 +static int taal_bl_get_intensity(struct backlight_device *dev)
3381 +{
3382 + if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
3383 + dev->props.power == FB_BLANK_UNBLANK)
3384 + return dev->props.brightness;
3385 +
3386 + return 0;
3387 +}
3388 +
3389 +static struct backlight_ops taal_bl_ops = {
3390 + .get_brightness = taal_bl_get_intensity,
3391 + .update_status = taal_bl_update_status,
3392 +};
3393 +
3394 +static void taal_get_timings(struct omap_dss_device *dssdev,
3395 + struct omap_video_timings *timings)
3396 +{
3397 + *timings = dssdev->panel.timings;
3398 +}
3399 +
3400 +static void taal_get_resolution(struct omap_dss_device *dssdev,
3401 + u16 *xres, u16 *yres)
3402 +{
3403 + struct taal_data *td = dev_get_drvdata(&dssdev->dev);
3404 +
3405 + if (td->rotate == 0 || td->rotate == 2) {
3406 + *xres = dssdev->panel.timings.x_res;
3407 + *yres = dssdev->panel.timings.y_res;
3408 + } else {
3409 + *yres = dssdev->panel.timings.x_res;
3410 + *xres = dssdev->panel.timings.y_res;
3411 + }
3412 +}
3413 +
3414 +static irqreturn_t taal_te_isr(int irq, void *data)
3415 +{
3416 + struct omap_dss_device *dssdev = data;
3417 + struct taal_data *td = dev_get_drvdata(&dssdev->dev);
3418 +
3419 + complete_all(&td->te_completion);
3420 +
3421 + return IRQ_HANDLED;
3422 +}
3423 +
3424 +static ssize_t taal_num_errors_show(struct device *dev,
3425 + struct device_attribute *attr, char *buf)
3426 +{
3427 + struct omap_dss_device *dssdev = to_dss_device(dev);
3428 + struct taal_data *td = dev_get_drvdata(&dssdev->dev);
3429 + u8 errors;
3430 + int r;
3431 +
3432 + if (td->enabled) {
3433 + dsi_bus_lock();
3434 + r = taal_dcs_read_1(DCS_READ_NUM_ERRORS, &errors);
3435 + dsi_bus_unlock();
3436 + } else {
3437 + r = -ENODEV;
3438 + }
3439 +
3440 + if (r)
3441 + return r;
3442 +
3443 + return snprintf(buf, PAGE_SIZE, "%d\n", errors);
3444 +}
3445 +
3446 +static ssize_t taal_hw_revision_show(struct device *dev,
3447 + struct device_attribute *attr, char *buf)
3448 +{
3449 + struct omap_dss_device *dssdev = to_dss_device(dev);
3450 + struct taal_data *td = dev_get_drvdata(&dssdev->dev);
3451 + u8 id1, id2, id3;
3452 + int r;
3453 +
3454 + if (td->enabled) {
3455 + dsi_bus_lock();
3456 + r = taal_get_id(&id1, &id2, &id3);
3457 + dsi_bus_unlock();
3458 + } else {
3459 + r = -ENODEV;
3460 + }
3461 +
3462 + if (r)
3463 + return r;
3464 +
3465 + return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x\n", id1, id2, id3);
3466 +}
3467 +
3468 +static const char *cabc_modes[] = {
3469 + "off", /* used also always when CABC is not supported */
3470 + "ui",
3471 + "still-image",
3472 + "moving-image",
3473 +};
3474 +
3475 +static ssize_t show_cabc_mode(struct device *dev,
3476 + struct device_attribute *attr,
3477 + char *buf)
3478 +{
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;
3482 + int mode;
3483 + int len;
3484 +
3485 + mode = td->cabc_mode;
3486 +
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);
3491 +
3492 + return len < PAGE_SIZE - 1 ? len : PAGE_SIZE - 1;
3493 +}
3494 +
3495 +static ssize_t store_cabc_mode(struct device *dev,
3496 + struct device_attribute *attr,
3497 + const char *buf, size_t count)
3498 +{
3499 + struct omap_dss_device *dssdev = to_dss_device(dev);
3500 + struct taal_data *td = dev_get_drvdata(&dssdev->dev);
3501 + int i;
3502 +
3503 + for (i = 0; i < ARRAY_SIZE(cabc_modes); i++) {
3504 + if (sysfs_streq(cabc_modes[i], buf))
3505 + break;
3506 + }
3507 +
3508 + if (i == ARRAY_SIZE(cabc_modes))
3509 + return -EINVAL;
3510 +
3511 + if (td->enabled) {
3512 + dsi_bus_lock();
3513 + if (!td->cabc_broken)
3514 + taal_dcs_write_1(DCS_WRITE_CABC, i);
3515 + dsi_bus_unlock();
3516 + }
3517 +
3518 + td->cabc_mode = i;
3519 +
3520 + return count;
3521 +}
3522 +
3523 +static ssize_t show_cabc_available_modes(struct device *dev,
3524 + struct device_attribute *attr,
3525 + char *buf)
3526 +{
3527 + int len;
3528 + int i;
3529 +
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" : "");
3535 +
3536 + return len < PAGE_SIZE ? len : PAGE_SIZE - 1;
3537 +}
3538 +
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);
3545 +
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,
3551 + NULL,
3552 +};
3553 +
3554 +static struct attribute_group taal_attr_group = {
3555 + .attrs = taal_attrs,
3556 +};
3557 +
3558 +static int taal_probe(struct omap_dss_device *dssdev)
3559 +{
3560 + struct taal_data *td;
3561 + struct backlight_device *bldev;
3562 + int r;
3563 +
3564 + const struct omap_video_timings taal_panel_timings = {
3565 + .x_res = 864,
3566 + .y_res = 480,
3567 + };
3568 +
3569 + dev_dbg(&dssdev->dev, "probe\n");
3570 +
3571 + dssdev->panel.config = OMAP_DSS_LCD_TFT;
3572 + dssdev->panel.timings = taal_panel_timings;
3573 + dssdev->ctrl.pixel_size = 24;
3574 +
3575 + td = kzalloc(sizeof(*td), GFP_KERNEL);
3576 + if (!td) {
3577 + r = -ENOMEM;
3578 + goto err0;
3579 + }
3580 +
3581 + dev_set_drvdata(&dssdev->dev, td);
3582 +
3583 + dssdev->get_timings = taal_get_timings;
3584 + dssdev->get_resolution = taal_get_resolution;
3585 +
3586 + /* if no platform set_backlight() defined, presume DSI backlight
3587 + * control */
3588 + if (!dssdev->set_backlight)
3589 + td->use_dsi_bl = true;
3590 +
3591 + bldev = backlight_device_register("taal", &dssdev->dev, dssdev,
3592 + &taal_bl_ops);
3593 + if (IS_ERR(bldev)) {
3594 + r = PTR_ERR(bldev);
3595 + goto err1;
3596 + }
3597 +
3598 + td->bldev = bldev;
3599 +
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;
3605 + } else {
3606 + bldev->props.max_brightness = 127;
3607 + bldev->props.brightness = 127;
3608 + }
3609 +
3610 + taal_bl_update_status(bldev);
3611 +
3612 + if (dssdev->phy.dsi.ext_te) {
3613 + int gpio = dssdev->phy.dsi.ext_te_gpio;
3614 +
3615 + r = gpio_request(gpio, "taal irq");
3616 + if (r) {
3617 + dev_err(&dssdev->dev, "GPIO request failed\n");
3618 + goto err2;
3619 + }
3620 +
3621 + gpio_direction_input(gpio);
3622 +
3623 + r = request_irq(gpio_to_irq(gpio), taal_te_isr,
3624 + IRQF_DISABLED | IRQF_TRIGGER_RISING,
3625 + "taal vsync", dssdev);
3626 +
3627 + if (r) {
3628 + dev_err(&dssdev->dev, "IRQ request failed\n");
3629 + gpio_free(gpio);
3630 + goto err2;
3631 + }
3632 +
3633 + init_completion(&td->te_completion);
3634 +
3635 + td->use_ext_te = true;
3636 + }
3637 +
3638 + r = sysfs_create_group(&dssdev->dev.kobj, &taal_attr_group);
3639 + if (r) {
3640 + dev_err(&dssdev->dev, "failed to create sysfs files\n");
3641 + goto err3;
3642 + }
3643 +
3644 + return 0;
3645 +err3:
3646 + if (td->use_ext_te) {
3647 + int gpio = dssdev->phy.dsi.ext_te_gpio;
3648 + free_irq(gpio_to_irq(gpio), dssdev);
3649 + gpio_free(gpio);
3650 + }
3651 +err2:
3652 + backlight_device_unregister(bldev);
3653 +err1:
3654 + kfree(td);
3655 +err0:
3656 + return r;
3657 +}
3658 +
3659 +static void taal_remove(struct omap_dss_device *dssdev)
3660 +{
3661 + struct taal_data *td = dev_get_drvdata(&dssdev->dev);
3662 + struct backlight_device *bldev;
3663 +
3664 + dev_dbg(&dssdev->dev, "remove\n");
3665 +
3666 + sysfs_remove_group(&dssdev->dev.kobj, &taal_attr_group);
3667 +
3668 + if (td->use_ext_te) {
3669 + int gpio = dssdev->phy.dsi.ext_te_gpio;
3670 + free_irq(gpio_to_irq(gpio), dssdev);
3671 + gpio_free(gpio);
3672 + }
3673 +
3674 + bldev = td->bldev;
3675 + bldev->props.power = FB_BLANK_POWERDOWN;
3676 + taal_bl_update_status(bldev);
3677 + backlight_device_unregister(bldev);
3678 +
3679 + kfree(td);
3680 +}
3681 +
3682 +static int taal_enable(struct omap_dss_device *dssdev)
3683 +{
3684 + struct taal_data *td = dev_get_drvdata(&dssdev->dev);
3685 + u8 id1, id2, id3;
3686 + int r;
3687 +
3688 + dev_dbg(&dssdev->dev, "enable\n");
3689 +
3690 + if (dssdev->platform_enable) {
3691 + r = dssdev->platform_enable(dssdev);
3692 + if (r)
3693 + return r;
3694 + }
3695 +
3696 + /* it seems we have to wait a bit until taal is ready */
3697 + msleep(5);
3698 +
3699 + r = taal_sleep_out(td);
3700 + if (r)
3701 + return r;
3702 +
3703 + r = taal_get_id(&id1, &id2, &id3);
3704 + if (r)
3705 + return r;
3706 +
3707 + /* on early revisions CABC is broken */
3708 + if (id2 == 0x00 || id2 == 0xff || id2 == 0x81)
3709 + td->cabc_broken = true;
3710 +
3711 + taal_dcs_write_1(DCS_BRIGHTNESS, 0xff);
3712 + taal_dcs_write_1(DCS_CTRL_DISPLAY, (1<<2) | (1<<5)); /* BL | BCTRL */
3713 +
3714 + taal_dcs_write_1(DCS_PIXEL_FORMAT, 0x7); /* 24bit/pixel */
3715 +
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);
3719 +
3720 + taal_dcs_write_0(DCS_DISPLAY_ON);
3721 +
3722 + td->enabled = 1;
3723 +
3724 + if (!td->intro_printed) {
3725 + dev_info(&dssdev->dev, "revision %02x.%02x.%02x\n",
3726 + id1, id2, id3);
3727 + if (td->cabc_broken)
3728 + dev_info(&dssdev->dev,
3729 + "old Taal version, CABC disabled\n");
3730 + td->intro_printed = true;
3731 + }
3732 +
3733 + return 0;
3734 +}
3735 +
3736 +static void taal_disable(struct omap_dss_device *dssdev)
3737 +{
3738 + struct taal_data *td = dev_get_drvdata(&dssdev->dev);
3739 +
3740 + dev_dbg(&dssdev->dev, "disable\n");
3741 +
3742 + taal_dcs_write_0(DCS_DISPLAY_OFF);
3743 + taal_sleep_in(td);
3744 +
3745 + /* wait a bit so that the message goes through */
3746 + msleep(10);
3747 +
3748 + if (dssdev->platform_disable)
3749 + dssdev->platform_disable(dssdev);
3750 +
3751 + td->enabled = 0;
3752 +}
3753 +
3754 +static int taal_suspend(struct omap_dss_device *dssdev)
3755 +{
3756 + struct taal_data *td = dev_get_drvdata(&dssdev->dev);
3757 + struct backlight_device *bldev = td->bldev;
3758 +
3759 + bldev->props.power = FB_BLANK_POWERDOWN;
3760 + taal_bl_update_status(bldev);
3761 +
3762 + return 0;
3763 +}
3764 +
3765 +static int taal_resume(struct omap_dss_device *dssdev)
3766 +{
3767 + struct taal_data *td = dev_get_drvdata(&dssdev->dev);
3768 + struct backlight_device *bldev = td->bldev;
3769 +
3770 + bldev->props.power = FB_BLANK_UNBLANK;
3771 + taal_bl_update_status(bldev);
3772 +
3773 + return 0;
3774 +}
3775 +
3776 +static void taal_setup_update(struct omap_dss_device *dssdev,
3777 + u16 x, u16 y, u16 w, u16 h)
3778 +{
3779 + taal_set_update_window(x, y, w, h);
3780 +}
3781 +
3782 +static int taal_enable_te(struct omap_dss_device *dssdev, bool enable)
3783 +{
3784 + struct taal_data *td = dev_get_drvdata(&dssdev->dev);
3785 + int r;
3786 +
3787 + td->te_enabled = enable;
3788 +
3789 + if (enable)
3790 + r = taal_dcs_write_1(DCS_TEAR_ON, 0);
3791 + else
3792 + r = taal_dcs_write_0(DCS_TEAR_OFF);
3793 +
3794 + return r;
3795 +}
3796 +
3797 +static int taal_wait_te(struct omap_dss_device *dssdev)
3798 +{
3799 + struct taal_data *td = dev_get_drvdata(&dssdev->dev);
3800 + long wait = msecs_to_jiffies(500);
3801 +
3802 + if (!td->use_ext_te || !td->te_enabled)
3803 + return 0;
3804 +
3805 + INIT_COMPLETION(td->te_completion);
3806 + wait = wait_for_completion_timeout(&td->te_completion, wait);
3807 + if (wait == 0) {
3808 + dev_err(&dssdev->dev, "timeout waiting TE\n");
3809 + return -ETIME;
3810 + }
3811 +
3812 + return 0;
3813 +}
3814 +
3815 +static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate)
3816 +{
3817 + struct taal_data *td = dev_get_drvdata(&dssdev->dev);
3818 + int r;
3819 +
3820 + dev_dbg(&dssdev->dev, "rotate %d\n", rotate);
3821 +
3822 + if (td->enabled) {
3823 + r = taal_set_addr_mode(rotate, td->mirror);
3824 +
3825 + if (r)
3826 + return r;
3827 + }
3828 +
3829 + td->rotate = rotate;
3830 +
3831 + return 0;
3832 +}
3833 +
3834 +static u8 taal_get_rotate(struct omap_dss_device *dssdev)
3835 +{
3836 + struct taal_data *td = dev_get_drvdata(&dssdev->dev);
3837 + return td->rotate;
3838 +}
3839 +
3840 +static int taal_mirror(struct omap_dss_device *dssdev, bool enable)
3841 +{
3842 + struct taal_data *td = dev_get_drvdata(&dssdev->dev);
3843 + int r;
3844 +
3845 + dev_dbg(&dssdev->dev, "mirror %d\n", enable);
3846 +
3847 + if (td->enabled) {
3848 + r = taal_set_addr_mode(td->rotate, enable);
3849 +
3850 + if (r)
3851 + return r;
3852 + }
3853 +
3854 + td->mirror = enable;
3855 +
3856 + return 0;
3857 +}
3858 +
3859 +static bool taal_get_mirror(struct omap_dss_device *dssdev)
3860 +{
3861 + struct taal_data *td = dev_get_drvdata(&dssdev->dev);
3862 + return td->mirror;
3863 +}
3864 +
3865 +static int taal_run_test(struct omap_dss_device *dssdev, int test_num)
3866 +{
3867 + u8 id1, id2, id3;
3868 + int r;
3869 +
3870 + r = taal_dcs_read_1(DCS_GET_ID1, &id1);
3871 + if (r)
3872 + return r;
3873 + r = taal_dcs_read_1(DCS_GET_ID2, &id2);
3874 + if (r)
3875 + return r;
3876 + r = taal_dcs_read_1(DCS_GET_ID3, &id3);
3877 + if (r)
3878 + return r;
3879 +
3880 + return 0;
3881 +}
3882 +
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)
3886 +{
3887 + int r;
3888 + int first = 1;
3889 + int plen;
3890 + unsigned buf_used = 0;
3891 +
3892 + if (size < w * h * 3)
3893 + return -ENOMEM;
3894 +
3895 + size = min(w * h * 3,
3896 + dssdev->panel.timings.x_res *
3897 + dssdev->panel.timings.y_res * 3);
3898 +
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
3901 + * an error. */
3902 + if (size % 2)
3903 + plen = 1;
3904 + else
3905 + plen = 2;
3906 +
3907 + taal_setup_update(dssdev, x, y, w, h);
3908 +
3909 + r = dsi_vc_set_max_rx_packet_size(TCH, plen);
3910 + if (r)
3911 + return r;
3912 +
3913 + while (buf_used < size) {
3914 + u8 dcs_cmd = first ? 0x2e : 0x3e;
3915 + first = 0;
3916 +
3917 + r = dsi_vc_dcs_read(TCH, dcs_cmd,
3918 + buf + buf_used, size - buf_used);
3919 +
3920 + if (r < 0) {
3921 + dev_err(&dssdev->dev, "read error\n");
3922 + goto err;
3923 + }
3924 +
3925 + buf_used += r;
3926 +
3927 + if (r < plen) {
3928 + dev_err(&dssdev->dev, "short read\n");
3929 + break;
3930 + }
3931 + }
3932 +
3933 + r = buf_used;
3934 +
3935 +err:
3936 + dsi_vc_set_max_rx_packet_size(TCH, 1);
3937 +
3938 + return r;
3939 +}
3940 +
3941 +static struct omap_dss_driver taal_driver = {
3942 + .probe = taal_probe,
3943 + .remove = taal_remove,
3944 +
3945 + .enable = taal_enable,
3946 + .disable = taal_disable,
3947 + .suspend = taal_suspend,
3948 + .resume = taal_resume,
3949 +
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,
3959 +
3960 + .driver = {
3961 + .name = "taal",
3962 + .owner = THIS_MODULE,
3963 + },
3964 +};
3965 +
3966 +static int __init taal_init(void)
3967 +{
3968 + omap_dss_register_driver(&taal_driver);
3969 +
3970 + return 0;
3971 +}
3972 +
3973 +static void __exit taal_exit(void)
3974 +{
3975 + omap_dss_unregister_driver(&taal_driver);
3976 +}
3977 +
3978 +module_init(taal_init);
3979 +module_exit(taal_exit);
3980 +
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
3987 --- /dev/null
3988 +++ b/drivers/video/omap2/dss/Kconfig
3989 @@ -0,0 +1,89 @@
3990 +menuconfig OMAP2_DSS
3991 + tristate "OMAP2/3 Display Subsystem support (EXPERIMENTAL)"
3992 + depends on ARCH_OMAP2 || ARCH_OMAP3
3993 + help
3994 + OMAP2/3 Display Subsystem support.
3995 +
3996 +if OMAP2_DSS
3997 +
3998 +config OMAP2_VRAM_SIZE
3999 + int "VRAM size (MB)"
4000 + range 0 32
4001 + default 0
4002 + help
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.
4006 +
4007 + You can also set this with "vram=<bytes>" kernel argument, or
4008 + in the board file.
4009 +
4010 +config OMAP2_DSS_DEBUG_SUPPORT
4011 + bool "Debug support"
4012 + default y
4013 + help
4014 + This enables debug messages. You need to enable printing
4015 + with 'debug' module parameter.
4016 +
4017 +config OMAP2_DSS_RFBI
4018 + bool "RFBI support"
4019 + default n
4020 + help
4021 + MIPI DBI, or RFBI (Remote Framebuffer Interface), support.
4022 +
4023 +config OMAP2_DSS_VENC
4024 + bool "VENC support"
4025 + default y
4026 + help
4027 + OMAP Video Encoder support.
4028 +
4029 +config OMAP2_DSS_SDI
4030 + bool "SDI support"
4031 + depends on ARCH_OMAP3
4032 + default n
4033 + help
4034 + SDI (Serial Display Interface) support.
4035 +
4036 +config OMAP2_DSS_DSI
4037 + bool "DSI support"
4038 + depends on ARCH_OMAP3
4039 + default n
4040 + help
4041 + MIPI DSI support.
4042 +
4043 +config OMAP2_DSS_USE_DSI_PLL
4044 + bool "Use DSI PLL for PCLK (EXPERIMENTAL)"
4045 + default n
4046 + depends on OMAP2_DSS_DSI
4047 + help
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.
4050 +
4051 +config OMAP2_DSS_FAKE_VSYNC
4052 + bool "Fake VSYNC irq from manual update displays"
4053 + default n
4054 + help
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,
4058 + time animation.
4059 +
4060 +config OMAP2_DSS_MIN_FCK_PER_PCK
4061 + int "Minimum FCK/PCK ratio (for scaling)"
4062 + range 0 32
4063 + default 0
4064 + help
4065 + This can be used to adjust the minimum FCK/PCK ratio.
4066 +
4067 + With this you can make sure that DISPC FCK is at least
4068 + n x PCK. Video plane scaling requires higher FCK than
4069 + normally.
4070 +
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).
4074 +
4075 + Max FCK is 173MHz, so this doesn't work if your PCK
4076 + is very high.
4077 +
4078 +endif
4079 diff --git a/drivers/video/omap2/dss/Makefile b/drivers/video/omap2/dss/Makefile
4080 new file mode 100644
4081 index 0000000..980c72c
4082 --- /dev/null
4083 +++ b/drivers/video/omap2/dss/Makefile
4084 @@ -0,0 +1,6 @@
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
4094 --- /dev/null
4095 +++ b/drivers/video/omap2/dss/core.c
4096 @@ -0,0 +1,917 @@
4097 +/*
4098 + * linux/drivers/video/omap2/dss/core.c
4099 + *
4100 + * Copyright (C) 2009 Nokia Corporation
4101 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
4102 + *
4103 + * Some code and ideas taken from drivers/video/omap/ driver
4104 + * by Imre Deak.
4105 + *
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.
4109 + *
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
4113 + * more details.
4114 + *
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/>.
4117 + */
4118 +
4119 +#define DSS_SUBSYS_NAME "CORE"
4120 +
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>
4130 +
4131 +#include <mach/display.h>
4132 +#include <mach/clock.h>
4133 +
4134 +#include "dss.h"
4135 +
4136 +static struct {
4137 + struct platform_device *pdev;
4138 + int ctx_id;
4139 +
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;
4146 +} core;
4147 +
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);
4152 +
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");
4156 +
4157 +#ifdef DEBUG
4158 +unsigned int dss_debug;
4159 +module_param_named(debug, dss_debug, bool, 0644);
4160 +#endif
4161 +
4162 +/* CONTEXT */
4163 +static int dss_get_ctx_id(void)
4164 +{
4165 + struct omap_dss_board_info *pdata = core.pdev->dev.platform_data;
4166 + int r;
4167 +
4168 + if (!pdata->get_last_off_on_transaction_id)
4169 + return 0;
4170 + r = pdata->get_last_off_on_transaction_id(&core.pdev->dev);
4171 + if (r < 0) {
4172 + dev_err(&core.pdev->dev, "getting transaction ID failed, "
4173 + "will force context restore\n");
4174 + r = -1;
4175 + }
4176 + return r;
4177 +}
4178 +
4179 +int dss_need_ctx_restore(void)
4180 +{
4181 + int id = dss_get_ctx_id();
4182 +
4183 + if (id < 0 || id != core.ctx_id) {
4184 + DSSDBG("ctx id %d -> id %d\n",
4185 + core.ctx_id, id);
4186 + core.ctx_id = id;
4187 + return 1;
4188 + } else {
4189 + return 0;
4190 + }
4191 +}
4192 +
4193 +static void save_all_ctx(void)
4194 +{
4195 + DSSDBG("save context\n");
4196 +
4197 + dss_clk_enable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK1);
4198 +
4199 + dss_save_context();
4200 + dispc_save_context();
4201 +#ifdef CONFIG_OMAP2_DSS_DSI
4202 + dsi_save_context();
4203 +#endif
4204 +
4205 + dss_clk_disable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK1);
4206 +}
4207 +
4208 +static void restore_all_ctx(void)
4209 +{
4210 + DSSDBG("restore context\n");
4211 +
4212 + dss_clk_enable_all_no_ctx();
4213 +
4214 + dss_restore_context();
4215 + dispc_restore_context();
4216 +#ifdef CONFIG_OMAP2_DSS_DSI
4217 + dsi_restore_context();
4218 +#endif
4219 +
4220 + dss_clk_disable_all_no_ctx();
4221 +}
4222 +
4223 +/* CLOCKS */
4224 +void dss_dump_clocks(struct seq_file *s)
4225 +{
4226 + int i;
4227 + struct clk *clocks[5] = {
4228 + core.dss_ick,
4229 + core.dss1_fck,
4230 + core.dss2_fck,
4231 + core.dss_54m_fck,
4232 + core.dss_96m_fck
4233 + };
4234 +
4235 + seq_printf(s, "- dss -\n");
4236 +
4237 + seq_printf(s, "internal clk count\t%u\n", core.num_clks_enabled);
4238 +
4239 + for (i = 0; i < 5; i++) {
4240 + if (!clocks[i])
4241 + continue;
4242 + seq_printf(s, "%-15s\t%lu\t%d\n",
4243 + clocks[i]->name,
4244 + clk_get_rate(clocks[i]),
4245 + clocks[i]->usecount);
4246 + }
4247 +}
4248 +
4249 +static int dss_get_clock(struct clk **clock, const char *clk_name)
4250 +{
4251 + struct clk *clk;
4252 +
4253 + clk = clk_get(&core.pdev->dev, clk_name);
4254 +
4255 + if (IS_ERR(clk)) {
4256 + DSSERR("can't get clock %s", clk_name);
4257 + return PTR_ERR(clk);
4258 + }
4259 +
4260 + *clock = clk;
4261 +
4262 + DSSDBG("clk %s, rate %ld\n", clk_name, clk_get_rate(clk));
4263 +
4264 + return 0;
4265 +}
4266 +
4267 +static int dss_get_clocks(void)
4268 +{
4269 + int r;
4270 +
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;
4276 +
4277 + r = dss_get_clock(&core.dss_ick, "ick");
4278 + if (r)
4279 + goto err;
4280 +
4281 + r = dss_get_clock(&core.dss1_fck, "dss1_fck");
4282 + if (r)
4283 + goto err;
4284 +
4285 + r = dss_get_clock(&core.dss2_fck, "dss2_fck");
4286 + if (r)
4287 + goto err;
4288 +
4289 + r = dss_get_clock(&core.dss_54m_fck, "tv_fck");
4290 + if (r)
4291 + goto err;
4292 +
4293 + r = dss_get_clock(&core.dss_96m_fck, "video_fck");
4294 + if (r)
4295 + goto err;
4296 +
4297 + return 0;
4298 +
4299 +err:
4300 + if (core.dss_ick)
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);
4310 +
4311 + return r;
4312 +}
4313 +
4314 +static void dss_put_clocks(void)
4315 +{
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);
4322 +}
4323 +
4324 +unsigned long dss_clk_get_rate(enum dss_clock clk)
4325 +{
4326 + switch (clk) {
4327 + case DSS_CLK_ICK:
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);
4333 + case DSS_CLK_54M:
4334 + return clk_get_rate(core.dss_54m_fck);
4335 + case DSS_CLK_96M:
4336 + return clk_get_rate(core.dss_96m_fck);
4337 + }
4338 +
4339 + BUG();
4340 + return 0;
4341 +}
4342 +
4343 +static unsigned count_clk_bits(enum dss_clock clks)
4344 +{
4345 + unsigned num_clks = 0;
4346 +
4347 + if (clks & DSS_CLK_ICK)
4348 + ++num_clks;
4349 + if (clks & DSS_CLK_FCK1)
4350 + ++num_clks;
4351 + if (clks & DSS_CLK_FCK2)
4352 + ++num_clks;
4353 + if (clks & DSS_CLK_54M)
4354 + ++num_clks;
4355 + if (clks & DSS_CLK_96M)
4356 + ++num_clks;
4357 +
4358 + return num_clks;
4359 +}
4360 +
4361 +static void dss_clk_enable_no_ctx(enum dss_clock clks)
4362 +{
4363 + unsigned num_clks = count_clk_bits(clks);
4364 +
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);
4375 +
4376 + core.num_clks_enabled += num_clks;
4377 +}
4378 +
4379 +void dss_clk_enable(enum dss_clock clks)
4380 +{
4381 + dss_clk_enable_no_ctx(clks);
4382 +
4383 + if (cpu_is_omap34xx() && dss_need_ctx_restore())
4384 + restore_all_ctx();
4385 +}
4386 +
4387 +static void dss_clk_disable_no_ctx(enum dss_clock clks)
4388 +{
4389 + unsigned num_clks = count_clk_bits(clks);
4390 +
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);
4401 +
4402 + core.num_clks_enabled -= num_clks;
4403 +}
4404 +
4405 +void dss_clk_disable(enum dss_clock clks)
4406 +{
4407 + if (cpu_is_omap34xx()) {
4408 + unsigned num_clks = count_clk_bits(clks);
4409 +
4410 + BUG_ON(core.num_clks_enabled < num_clks);
4411 +
4412 + if (core.num_clks_enabled == num_clks)
4413 + save_all_ctx();
4414 + }
4415 +
4416 + dss_clk_disable_no_ctx(clks);
4417 +}
4418 +
4419 +static void dss_clk_enable_all_no_ctx(void)
4420 +{
4421 + enum dss_clock clks;
4422 +
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);
4427 +}
4428 +
4429 +static void dss_clk_disable_all_no_ctx(void)
4430 +{
4431 + enum dss_clock clks;
4432 +
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);
4437 +}
4438 +
4439 +static void dss_clk_disable_all(void)
4440 +{
4441 + enum dss_clock clks;
4442 +
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);
4447 +}
4448 +
4449 +/* DEBUGFS */
4450 +#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
4451 +static void dss_debug_dump_clocks(struct seq_file *s)
4452 +{
4453 + dss_dump_clocks(s);
4454 + dispc_dump_clocks(s);
4455 +#ifdef CONFIG_OMAP2_DSS_DSI
4456 + dsi_dump_clocks(s);
4457 +#endif
4458 +}
4459 +
4460 +static int dss_debug_show(struct seq_file *s, void *unused)
4461 +{
4462 + void (*func)(struct seq_file *) = s->private;
4463 + func(s);
4464 + return 0;
4465 +}
4466 +
4467 +static int dss_debug_open(struct inode *inode, struct file *file)
4468 +{
4469 + return single_open(file, dss_debug_show, inode->i_private);
4470 +}
4471 +
4472 +static const struct file_operations dss_debug_fops = {
4473 + .open = dss_debug_open,
4474 + .read = seq_read,
4475 + .llseek = seq_lseek,
4476 + .release = single_release,
4477 +};
4478 +
4479 +static struct dentry *dss_debugfs_dir;
4480 +
4481 +static int dss_initialize_debugfs(void)
4482 +{
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;
4487 + return err;
4488 + }
4489 +
4490 + debugfs_create_file("clk", S_IRUGO, dss_debugfs_dir,
4491 + &dss_debug_dump_clocks, &dss_debug_fops);
4492 +
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);
4500 +#endif
4501 +#ifdef CONFIG_OMAP2_DSS_DSI
4502 + debugfs_create_file("dsi", S_IRUGO, dss_debugfs_dir,
4503 + &dsi_dump_regs, &dss_debug_fops);
4504 +#endif
4505 +#ifdef CONFIG_OMAP2_DSS_VENC
4506 + debugfs_create_file("venc", S_IRUGO, dss_debugfs_dir,
4507 + &venc_dump_regs, &dss_debug_fops);
4508 +#endif
4509 + return 0;
4510 +}
4511 +
4512 +static void dss_uninitialize_debugfs(void)
4513 +{
4514 + if (dss_debugfs_dir)
4515 + debugfs_remove_recursive(dss_debugfs_dir);
4516 +}
4517 +#endif /* CONFIG_DEBUG_FS && CONFIG_OMAP2_DSS_DEBUG_SUPPORT */
4518 +
4519 +/* PLATFORM DEVICE */
4520 +static int omap_dss_probe(struct platform_device *pdev)
4521 +{
4522 + struct omap_dss_board_info *pdata = pdev->dev.platform_data;
4523 + int skip_init = 0;
4524 + int r;
4525 + int i;
4526 +
4527 + core.pdev = pdev;
4528 +
4529 + dss_init_overlay_managers(pdev);
4530 + dss_init_overlays(pdev);
4531 +
4532 + r = dss_get_clocks();
4533 + if (r)
4534 + goto fail0;
4535 +
4536 + dss_clk_enable_all_no_ctx();
4537 +
4538 + core.ctx_id = dss_get_ctx_id();
4539 + DSSDBG("initial ctx id %u\n", core.ctx_id);
4540 +
4541 +#ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT
4542 + /* DISPC_CONTROL */
4543 + if (omap_readl(0x48050440) & 1) /* LCD enabled? */
4544 + skip_init = 1;
4545 +#endif
4546 +
4547 + r = dss_init(skip_init);
4548 + if (r) {
4549 + DSSERR("Failed to initialize DSS\n");
4550 + goto fail0;
4551 + }
4552 +
4553 +#ifdef CONFIG_OMAP2_DSS_RFBI
4554 + r = rfbi_init();
4555 + if (r) {
4556 + DSSERR("Failed to initialize rfbi\n");
4557 + goto fail0;
4558 + }
4559 +#endif
4560 +
4561 + r = dpi_init();
4562 + if (r) {
4563 + DSSERR("Failed to initialize dpi\n");
4564 + goto fail0;
4565 + }
4566 +
4567 + r = dispc_init();
4568 + if (r) {
4569 + DSSERR("Failed to initialize dispc\n");
4570 + goto fail0;
4571 + }
4572 +#ifdef CONFIG_OMAP2_DSS_VENC
4573 + r = venc_init(pdev);
4574 + if (r) {
4575 + DSSERR("Failed to initialize venc\n");
4576 + goto fail0;
4577 + }
4578 +#endif
4579 + if (cpu_is_omap34xx()) {
4580 +#ifdef CONFIG_OMAP2_DSS_SDI
4581 + r = sdi_init(skip_init);
4582 + if (r) {
4583 + DSSERR("Failed to initialize SDI\n");
4584 + goto fail0;
4585 + }
4586 +#endif
4587 +#ifdef CONFIG_OMAP2_DSS_DSI
4588 + r = dsi_init(pdev);
4589 + if (r) {
4590 + DSSERR("Failed to initialize DSI\n");
4591 + goto fail0;
4592 + }
4593 +#endif
4594 + }
4595 +
4596 +#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
4597 + r = dss_initialize_debugfs();
4598 + if (r)
4599 + goto fail0;
4600 +#endif
4601 +
4602 + for (i = 0; i < pdata->num_devices; ++i) {
4603 + struct omap_dss_device *dssdev = pdata->devices[i];
4604 +
4605 + r = omap_dss_register_device(dssdev);
4606 + if (r)
4607 + DSSERR("device reg failed %d\n", i);
4608 +
4609 + if (def_disp_name && strcmp(def_disp_name, dssdev->name) == 0)
4610 + pdata->default_device = dssdev;
4611 + }
4612 +
4613 + dss_clk_disable_all();
4614 +
4615 + return 0;
4616 +
4617 + /* XXX fail correctly */
4618 +fail0:
4619 + return r;
4620 +}
4621 +
4622 +static int omap_dss_remove(struct platform_device *pdev)
4623 +{
4624 + struct omap_dss_board_info *pdata = pdev->dev.platform_data;
4625 + int i;
4626 + int c;
4627 +
4628 +#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
4629 + dss_uninitialize_debugfs();
4630 +#endif
4631 +
4632 +#ifdef CONFIG_OMAP2_DSS_VENC
4633 + venc_exit();
4634 +#endif
4635 + dispc_exit();
4636 + dpi_exit();
4637 +#ifdef CONFIG_OMAP2_DSS_RFBI
4638 + rfbi_exit();
4639 +#endif
4640 + if (cpu_is_omap34xx()) {
4641 +#ifdef CONFIG_OMAP2_DSS_DSI
4642 + dsi_exit();
4643 +#endif
4644 +#ifdef CONFIG_OMAP2_DSS_SDI
4645 + sdi_exit();
4646 +#endif
4647 + }
4648 +
4649 + dss_exit();
4650 +
4651 + /* these should be removed at some point */
4652 + c = core.dss_ick->usecount;
4653 + if (c > 0) {
4654 + DSSERR("warning: dss_ick usecount %d, disabling\n", c);
4655 + while (c-- > 0)
4656 + clk_disable(core.dss_ick);
4657 + }
4658 +
4659 + c = core.dss1_fck->usecount;
4660 + if (c > 0) {
4661 + DSSERR("warning: dss1_fck usecount %d, disabling\n", c);
4662 + while (c-- > 0)
4663 + clk_disable(core.dss1_fck);
4664 + }
4665 +
4666 + c = core.dss2_fck->usecount;
4667 + if (c > 0) {
4668 + DSSERR("warning: dss2_fck usecount %d, disabling\n", c);
4669 + while (c-- > 0)
4670 + clk_disable(core.dss2_fck);
4671 + }
4672 +
4673 + c = core.dss_54m_fck->usecount;
4674 + if (c > 0) {
4675 + DSSERR("warning: dss_54m_fck usecount %d, disabling\n", c);
4676 + while (c-- > 0)
4677 + clk_disable(core.dss_54m_fck);
4678 + }
4679 +
4680 + if (core.dss_96m_fck) {
4681 + c = core.dss_96m_fck->usecount;
4682 + if (c > 0) {
4683 + DSSERR("warning: dss_96m_fck usecount %d, disabling\n",
4684 + c);
4685 + while (c-- > 0)
4686 + clk_disable(core.dss_96m_fck);
4687 + }
4688 + }
4689 +
4690 + dss_put_clocks();
4691 +
4692 + dss_uninit_overlays(pdev);
4693 + dss_uninit_overlay_managers(pdev);
4694 +
4695 + for (i = 0; i < pdata->num_devices; ++i)
4696 + omap_dss_unregister_device(pdata->devices[i]);
4697 +
4698 + return 0;
4699 +}
4700 +
4701 +static void omap_dss_shutdown(struct platform_device *pdev)
4702 +{
4703 + DSSDBG("shutdown\n");
4704 +}
4705 +
4706 +static int omap_dss_suspend(struct platform_device *pdev, pm_message_t state)
4707 +{
4708 + DSSDBG("suspend %d\n", state.event);
4709 +
4710 + return dss_suspend_all_devices();
4711 +}
4712 +
4713 +static int omap_dss_resume(struct platform_device *pdev)
4714 +{
4715 + DSSDBG("resume\n");
4716 +
4717 + return dss_resume_all_devices();
4718 +}
4719 +
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,
4726 + .driver = {
4727 + .name = "omapdss",
4728 + .owner = THIS_MODULE,
4729 + },
4730 +};
4731 +
4732 +/* BUS */
4733 +static int dss_bus_match(struct device *dev, struct device_driver *driver)
4734 +{
4735 + struct omap_dss_device *dssdev = to_dss_device(dev);
4736 +
4737 + DSSDBG("bus_match. dev %s/%s, drv %s\n",
4738 + dev_name(dev), dssdev->driver_name, driver->name);
4739 +
4740 + return strcmp(dssdev->driver_name, driver->name) == 0;
4741 +}
4742 +
4743 +static ssize_t device_name_show(struct device *dev,
4744 + struct device_attribute *attr, char *buf)
4745 +{
4746 + struct omap_dss_device *dssdev = to_dss_device(dev);
4747 + return snprintf(buf, PAGE_SIZE, "%s\n",
4748 + dssdev->name ?
4749 + dssdev->name : "");
4750 +}
4751 +
4752 +static struct device_attribute default_dev_attrs[] = {
4753 + __ATTR(name, S_IRUGO, device_name_show, NULL),
4754 + __ATTR_NULL,
4755 +};
4756 +
4757 +static ssize_t driver_name_show(struct device_driver *drv, char *buf)
4758 +{
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 : "");
4763 +}
4764 +static struct driver_attribute default_drv_attrs[] = {
4765 + __ATTR(name, S_IRUGO, driver_name_show, NULL),
4766 + __ATTR_NULL,
4767 +};
4768 +
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,
4774 +};
4775 +
4776 +static void dss_bus_release(struct device *dev)
4777 +{
4778 + DSSDBG("bus_release\n");
4779 +}
4780 +
4781 +static struct device dss_bus = {
4782 + .release = dss_bus_release,
4783 +};
4784 +
4785 +struct bus_type *dss_get_bus(void)
4786 +{
4787 + return &dss_bus_type;
4788 +}
4789 +
4790 +/* DRIVER */
4791 +static int dss_driver_probe(struct device *dev)
4792 +{
4793 + int r;
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;
4797 + bool force;
4798 +
4799 + DSSDBG("driver_probe: dev %s/%s, drv %s\n",
4800 + dev_name(dev), dssdev->driver_name,
4801 + dssdrv->driver.name);
4802 +
4803 + dss_init_device(core.pdev, dssdev);
4804 +
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);
4809 + }
4810 +
4811 + r = dssdrv->probe(dssdev);
4812 +
4813 + if (r) {
4814 + DSSERR("driver probe failed: %d\n", r);
4815 + return r;
4816 + }
4817 +
4818 + DSSDBG("probe done for device %s\n", dev_name(dev));
4819 +
4820 + dssdev->driver = dssdrv;
4821 +
4822 + return 0;
4823 +}
4824 +
4825 +static int dss_driver_remove(struct device *dev)
4826 +{
4827 + struct omap_dss_driver *dssdrv = to_dss_driver(dev->driver);
4828 + struct omap_dss_device *dssdev = to_dss_device(dev);
4829 +
4830 + DSSDBG("driver_remove: dev %s/%s\n", dev_name(dev),
4831 + dssdev->driver_name);
4832 +
4833 + dssdrv->remove(dssdev);
4834 +
4835 + dss_uninit_device(core.pdev, dssdev);
4836 +
4837 + dssdev->driver = NULL;
4838 +
4839 + return 0;
4840 +}
4841 +
4842 +int omap_dss_register_driver(struct omap_dss_driver *dssdriver)
4843 +{
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);
4848 +}
4849 +EXPORT_SYMBOL(omap_dss_register_driver);
4850 +
4851 +void omap_dss_unregister_driver(struct omap_dss_driver *dssdriver)
4852 +{
4853 + driver_unregister(&dssdriver->driver);
4854 +}
4855 +EXPORT_SYMBOL(omap_dss_unregister_driver);
4856 +
4857 +/* DEVICE */
4858 +static void reset_device(struct device *dev, int check)
4859 +{
4860 + u8 *dev_p = (u8 *)dev;
4861 + u8 *dev_end = dev_p + sizeof(*dev);
4862 + void *saved_pdata;
4863 +
4864 + saved_pdata = dev->platform_data;
4865 + if (check) {
4866 + /*
4867 + * Check if there is any other setting than platform_data
4868 + * in struct device; warn that these will be reset by our
4869 + * init.
4870 + */
4871 + dev->platform_data = NULL;
4872 + while (dev_p < dev_end) {
4873 + if (*dev_p) {
4874 + WARN("%s: struct device fields will be "
4875 + "discarded\n",
4876 + __func__);
4877 + break;
4878 + }
4879 + dev_p++;
4880 + }
4881 + }
4882 + memset(dev, 0, sizeof(*dev));
4883 + dev->platform_data = saved_pdata;
4884 +}
4885 +
4886 +
4887 +static void omap_dss_dev_release(struct device *dev)
4888 +{
4889 + reset_device(dev, 0);
4890 +}
4891 +
4892 +int omap_dss_register_device(struct omap_dss_device *dssdev)
4893 +{
4894 + static int dev_num;
4895 + static int panel_num;
4896 + int r;
4897 +
4898 + WARN_ON(!dssdev->driver_name);
4899 +
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);
4906 + if (r)
4907 + return r;
4908 +
4909 + if (dssdev->ctrl.panel) {
4910 + struct omap_dss_device *panel = dssdev->ctrl.panel;
4911 +
4912 + panel->panel.ctrl = dssdev;
4913 +
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);
4920 + if (r)
4921 + return r;
4922 + }
4923 +
4924 + return 0;
4925 +}
4926 +
4927 +void omap_dss_unregister_device(struct omap_dss_device *dssdev)
4928 +{
4929 + device_unregister(&dssdev->dev);
4930 +
4931 + if (dssdev->ctrl.panel) {
4932 + struct omap_dss_device *panel = dssdev->ctrl.panel;
4933 + device_unregister(&panel->dev);
4934 + }
4935 +}
4936 +
4937 +/* BUS */
4938 +static int omap_dss_bus_register(void)
4939 +{
4940 + int r;
4941 +
4942 + r = bus_register(&dss_bus_type);
4943 + if (r) {
4944 + DSSERR("bus register failed\n");
4945 + return r;
4946 + }
4947 +
4948 + dev_set_name(&dss_bus, "omapdss");
4949 + r = device_register(&dss_bus);
4950 + if (r) {
4951 + DSSERR("bus driver register failed\n");
4952 + bus_unregister(&dss_bus_type);
4953 + return r;
4954 + }
4955 +
4956 + return 0;
4957 +}
4958 +
4959 +/* INIT */
4960 +
4961 +#ifdef CONFIG_OMAP2_DSS_MODULE
4962 +static void omap_dss_bus_unregister(void)
4963 +{
4964 + device_unregister(&dss_bus);
4965 +
4966 + bus_unregister(&dss_bus_type);
4967 +}
4968 +
4969 +static int __init omap_dss_init(void)
4970 +{
4971 + int r;
4972 +
4973 + r = omap_dss_bus_register();
4974 + if (r)
4975 + return r;
4976 +
4977 + r = platform_driver_register(&omap_dss_driver);
4978 + if (r) {
4979 + omap_dss_bus_unregister();
4980 + return r;
4981 + }
4982 +
4983 + return 0;
4984 +}
4985 +
4986 +static void __exit omap_dss_exit(void)
4987 +{
4988 + platform_driver_unregister(&omap_dss_driver);
4989 +
4990 + omap_dss_bus_unregister();
4991 +}
4992 +
4993 +module_init(omap_dss_init);
4994 +module_exit(omap_dss_exit);
4995 +#else
4996 +static int __init omap_dss_init(void)
4997 +{
4998 + return omap_dss_bus_register();
4999 +}
5000 +
5001 +static int __init omap_dss_init2(void)
5002 +{
5003 + return platform_driver_register(&omap_dss_driver);
5004 +}
5005 +
5006 +core_initcall(omap_dss_init);
5007 +device_initcall(omap_dss_init2);
5008 +#endif
5009 +
5010 +MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>");
5011 +MODULE_DESCRIPTION("OMAP2/3 Display Subsystem");
5012 +MODULE_LICENSE("GPL v2");
5013 +
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
5017 --- /dev/null
5018 +++ b/drivers/video/omap2/dss/dispc.c
5019 @@ -0,0 +1,3182 @@
5020 +/*
5021 + * linux/drivers/video/omap2/dss/dispc.c
5022 + *
5023 + * Copyright (C) 2009 Nokia Corporation
5024 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
5025 + *
5026 + * Some code and ideas taken from drivers/video/omap/ driver
5027 + * by Imre Deak.
5028 + *
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.
5032 + *
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
5036 + * more details.
5037 + *
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/>.
5040 + */
5041 +
5042 +#define DSS_SUBSYS_NAME "DISPC"
5043 +
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>
5053 +
5054 +#include <mach/sram.h>
5055 +#include <mach/board.h>
5056 +#include <mach/clock.h>
5057 +
5058 +#include <mach/display.h>
5059 +
5060 +#include "dss.h"
5061 +
5062 +/* DISPC */
5063 +#define DISPC_BASE 0x48050400
5064 +
5065 +#define DISPC_SZ_REGS SZ_1K
5066 +
5067 +struct dispc_reg { u16 idx; };
5068 +
5069 +#define DISPC_REG(idx) ((const struct dispc_reg) { idx })
5070 +
5071 +/* DISPC common */
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)
5093 +
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)
5106 +
5107 +#define DISPC_DATA_CYCLE1 DISPC_REG(0x01D4)
5108 +#define DISPC_DATA_CYCLE2 DISPC_REG(0x01D8)
5109 +#define DISPC_DATA_CYCLE3 DISPC_REG(0x01DC)
5110 +
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)
5114 +
5115 +#define DISPC_GFX_PRELOAD DISPC_REG(0x022C)
5116 +
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)
5119 +
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)
5133 +
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)
5142 +
5143 +#define DISPC_VID_PRELOAD(n) DISPC_REG(0x230 + (n)*0x04)
5144 +
5145 +
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)
5152 +
5153 +#define DISPC_MAX_NR_ISRS 8
5154 +
5155 +struct omap_dispc_isr_data {
5156 + omap_dispc_isr_t isr;
5157 + void *arg;
5158 + u32 mask;
5159 +};
5160 +
5161 +#define REG_GET(idx, start, end) \
5162 + FLD_GET(dispc_read_reg(idx), start, end)
5163 +
5164 +#define REG_FLD_MOD(idx, val, start, end) \
5165 + dispc_write_reg(idx, FLD_MOD(dispc_read_reg(idx), val, start, end))
5166 +
5167 +static const struct dispc_reg dispc_reg_att[] = { DISPC_GFX_ATTRIBUTES,
5168 + DISPC_VID_ATTRIBUTES(0),
5169 + DISPC_VID_ATTRIBUTES(1) };
5170 +
5171 +static struct {
5172 + void __iomem *base;
5173 +
5174 + struct clk *dpll4_m4_ck;
5175 +
5176 + unsigned long cache_req_pck;
5177 + unsigned long cache_prate;
5178 + struct dispc_clock_info cache_cinfo;
5179 +
5180 + u32 fifo_size[3];
5181 +
5182 + spinlock_t irq_lock;
5183 + u32 irq_error_mask;
5184 + struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
5185 + u32 error_irqs;
5186 + struct work_struct error_work;
5187 +
5188 + u32 ctx[DISPC_SZ_REGS / sizeof(u32)];
5189 +} dispc;
5190 +
5191 +static void _omap_dispc_set_irqs(void);
5192 +
5193 +static inline void dispc_write_reg(const struct dispc_reg idx, u32 val)
5194 +{
5195 + __raw_writel(val, dispc.base + idx.idx);
5196 +}
5197 +
5198 +static inline u32 dispc_read_reg(const struct dispc_reg idx)
5199 +{
5200 + return __raw_readl(dispc.base + idx.idx);
5201 +}
5202 +
5203 +#define SR(reg) \
5204 + dispc.ctx[(DISPC_##reg).idx / sizeof(u32)] = dispc_read_reg(DISPC_##reg)
5205 +#define RR(reg) \
5206 + dispc_write_reg(DISPC_##reg, dispc.ctx[(DISPC_##reg).idx / sizeof(u32)])
5207 +
5208 +void dispc_save_context(void)
5209 +{
5210 + if (cpu_is_omap24xx())
5211 + return;
5212 +
5213 + SR(SYSCONFIG);
5214 + SR(IRQENABLE);
5215 + SR(CONTROL);
5216 + SR(CONFIG);
5217 + SR(DEFAULT_COLOR0);
5218 + SR(DEFAULT_COLOR1);
5219 + SR(TRANS_COLOR0);
5220 + SR(TRANS_COLOR1);
5221 + SR(LINE_NUMBER);
5222 + SR(TIMING_H);
5223 + SR(TIMING_V);
5224 + SR(POL_FREQ);
5225 + SR(DIVISOR);
5226 + SR(GLOBAL_ALPHA);
5227 + SR(SIZE_DIG);
5228 + SR(SIZE_LCD);
5229 +
5230 + SR(GFX_BA0);
5231 + SR(GFX_BA1);
5232 + SR(GFX_POSITION);
5233 + SR(GFX_SIZE);
5234 + SR(GFX_ATTRIBUTES);
5235 + SR(GFX_FIFO_THRESHOLD);
5236 + SR(GFX_ROW_INC);
5237 + SR(GFX_PIXEL_INC);
5238 + SR(GFX_WINDOW_SKIP);
5239 + SR(GFX_TABLE_BA);
5240 +
5241 + SR(DATA_CYCLE1);
5242 + SR(DATA_CYCLE2);
5243 + SR(DATA_CYCLE3);
5244 +
5245 + SR(CPR_COEF_R);
5246 + SR(CPR_COEF_G);
5247 + SR(CPR_COEF_B);
5248 +
5249 + SR(GFX_PRELOAD);
5250 +
5251 + /* VID1 */
5252 + SR(VID_BA0(0));
5253 + SR(VID_BA1(0));
5254 + SR(VID_POSITION(0));
5255 + SR(VID_SIZE(0));
5256 + SR(VID_ATTRIBUTES(0));
5257 + SR(VID_FIFO_THRESHOLD(0));
5258 + SR(VID_ROW_INC(0));
5259 + SR(VID_PIXEL_INC(0));
5260 + SR(VID_FIR(0));
5261 + SR(VID_PICTURE_SIZE(0));
5262 + SR(VID_ACCU0(0));
5263 + SR(VID_ACCU1(0));
5264 +
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));
5273 +
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));
5282 +
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));
5288 +
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));
5297 +
5298 + SR(VID_PRELOAD(0));
5299 +
5300 + /* VID2 */
5301 + SR(VID_BA0(1));
5302 + SR(VID_BA1(1));
5303 + SR(VID_POSITION(1));
5304 + SR(VID_SIZE(1));
5305 + SR(VID_ATTRIBUTES(1));
5306 + SR(VID_FIFO_THRESHOLD(1));
5307 + SR(VID_ROW_INC(1));
5308 + SR(VID_PIXEL_INC(1));
5309 + SR(VID_FIR(1));
5310 + SR(VID_PICTURE_SIZE(1));
5311 + SR(VID_ACCU0(1));
5312 + SR(VID_ACCU1(1));
5313 +
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));
5322 +
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));
5331 +
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));
5337 +
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));
5346 +
5347 + SR(VID_PRELOAD(1));
5348 +}
5349 +
5350 +void dispc_restore_context(void)
5351 +{
5352 + RR(SYSCONFIG);
5353 + RR(IRQENABLE);
5354 + /*RR(CONTROL);*/
5355 + RR(CONFIG);
5356 + RR(DEFAULT_COLOR0);
5357 + RR(DEFAULT_COLOR1);
5358 + RR(TRANS_COLOR0);
5359 + RR(TRANS_COLOR1);
5360 + RR(LINE_NUMBER);
5361 + RR(TIMING_H);
5362 + RR(TIMING_V);
5363 + RR(POL_FREQ);
5364 + RR(DIVISOR);
5365 + RR(GLOBAL_ALPHA);
5366 + RR(SIZE_DIG);
5367 + RR(SIZE_LCD);
5368 +
5369 + RR(GFX_BA0);
5370 + RR(GFX_BA1);
5371 + RR(GFX_POSITION);
5372 + RR(GFX_SIZE);
5373 + RR(GFX_ATTRIBUTES);
5374 + RR(GFX_FIFO_THRESHOLD);
5375 + RR(GFX_ROW_INC);
5376 + RR(GFX_PIXEL_INC);
5377 + RR(GFX_WINDOW_SKIP);
5378 + RR(GFX_TABLE_BA);
5379 +
5380 + RR(DATA_CYCLE1);
5381 + RR(DATA_CYCLE2);
5382 + RR(DATA_CYCLE3);
5383 +
5384 + RR(CPR_COEF_R);
5385 + RR(CPR_COEF_G);
5386 + RR(CPR_COEF_B);
5387 +
5388 + RR(GFX_PRELOAD);
5389 +
5390 + /* VID1 */
5391 + RR(VID_BA0(0));
5392 + RR(VID_BA1(0));
5393 + RR(VID_POSITION(0));
5394 + RR(VID_SIZE(0));
5395 + RR(VID_ATTRIBUTES(0));
5396 + RR(VID_FIFO_THRESHOLD(0));
5397 + RR(VID_ROW_INC(0));
5398 + RR(VID_PIXEL_INC(0));
5399 + RR(VID_FIR(0));
5400 + RR(VID_PICTURE_SIZE(0));
5401 + RR(VID_ACCU0(0));
5402 + RR(VID_ACCU1(0));
5403 +
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));
5412 +
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));
5421 +
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));
5427 +
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));
5436 +
5437 + RR(VID_PRELOAD(0));
5438 +
5439 + /* VID2 */
5440 + RR(VID_BA0(1));
5441 + RR(VID_BA1(1));
5442 + RR(VID_POSITION(1));
5443 + RR(VID_SIZE(1));
5444 + RR(VID_ATTRIBUTES(1));
5445 + RR(VID_FIFO_THRESHOLD(1));
5446 + RR(VID_ROW_INC(1));
5447 + RR(VID_PIXEL_INC(1));
5448 + RR(VID_FIR(1));
5449 + RR(VID_PICTURE_SIZE(1));
5450 + RR(VID_ACCU0(1));
5451 + RR(VID_ACCU1(1));
5452 +
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));
5461 +
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));
5470 +
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));
5476 +
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));
5485 +
5486 + RR(VID_PRELOAD(1));
5487 +
5488 + /* enable last, because LCD & DIGIT enable are here */
5489 + RR(CONTROL);
5490 +}
5491 +
5492 +#undef SR
5493 +#undef RR
5494 +
5495 +static inline void enable_clocks(bool enable)
5496 +{
5497 + if (enable)
5498 + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
5499 + else
5500 + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
5501 +}
5502 +
5503 +bool dispc_go_busy(enum omap_channel channel)
5504 +{
5505 + int bit;
5506 +
5507 + if (channel == OMAP_DSS_CHANNEL_LCD)
5508 + bit = 5; /* GOLCD */
5509 + else
5510 + bit = 6; /* GODIGIT */
5511 +
5512 + return REG_GET(DISPC_CONTROL, bit, bit) == 1;
5513 +}
5514 +
5515 +void dispc_go(enum omap_channel channel)
5516 +{
5517 + int bit;
5518 +
5519 + enable_clocks(1);
5520 +
5521 + if (channel == OMAP_DSS_CHANNEL_LCD)
5522 + bit = 0; /* LCDENABLE */
5523 + else
5524 + bit = 1; /* DIGITALENABLE */
5525 +
5526 + /* if the channel is not enabled, we don't need GO */
5527 + if (REG_GET(DISPC_CONTROL, bit, bit) == 0)
5528 + goto end;
5529 +
5530 + if (channel == OMAP_DSS_CHANNEL_LCD)
5531 + bit = 5; /* GOLCD */
5532 + else
5533 + bit = 6; /* GODIGIT */
5534 +
5535 + if (REG_GET(DISPC_CONTROL, bit, bit) == 1) {
5536 + DSSERR("GO bit not down for channel %d\n", channel);
5537 + goto end;
5538 + }
5539 +
5540 + DSSDBG("GO %s\n", channel == OMAP_DSS_CHANNEL_LCD ? "LCD" : "DIGIT");
5541 +
5542 + REG_FLD_MOD(DISPC_CONTROL, 1, bit, bit);
5543 +end:
5544 + enable_clocks(0);
5545 +}
5546 +
5547 +static void _dispc_write_firh_reg(enum omap_plane plane, int reg, u32 value)
5548 +{
5549 + BUG_ON(plane == OMAP_DSS_GFX);
5550 +
5551 + dispc_write_reg(DISPC_VID_FIR_COEF_H(plane-1, reg), value);
5552 +}
5553 +
5554 +static void _dispc_write_firhv_reg(enum omap_plane plane, int reg, u32 value)
5555 +{
5556 + BUG_ON(plane == OMAP_DSS_GFX);
5557 +
5558 + dispc_write_reg(DISPC_VID_FIR_COEF_HV(plane-1, reg), value);
5559 +}
5560 +
5561 +static void _dispc_write_firv_reg(enum omap_plane plane, int reg, u32 value)
5562 +{
5563 + BUG_ON(plane == OMAP_DSS_GFX);
5564 +
5565 + dispc_write_reg(DISPC_VID_FIR_COEF_V(plane-1, reg), value);
5566 +}
5567 +
5568 +static void _dispc_set_scale_coef(enum omap_plane plane, int hscaleup,
5569 + int vscaleup, int five_taps)
5570 +{
5571 + /* Coefficients for horizontal up-sampling */
5572 + static const u32 coef_hup[8] = {
5573 + 0x00800000,
5574 + 0x0D7CF800,
5575 + 0x1E70F5FF,
5576 + 0x335FF5FE,
5577 + 0xF74949F7,
5578 + 0xF55F33FB,
5579 + 0xF5701EFE,
5580 + 0xF87C0DFF,
5581 + };
5582 +
5583 + /* Coefficients for horizontal down-sampling */
5584 + static const u32 coef_hdown[8] = {
5585 + 0x24382400,
5586 + 0x28371FFE,
5587 + 0x2C361BFB,
5588 + 0x303516F9,
5589 + 0x11343311,
5590 + 0x1635300C,
5591 + 0x1B362C08,
5592 + 0x1F372804,
5593 + };
5594 +
5595 + /* Coefficients for horizontal and vertical up-sampling */
5596 + static const u32 coef_hvup[2][8] = {
5597 + {
5598 + 0x00800000,
5599 + 0x037B02FF,
5600 + 0x0C6F05FE,
5601 + 0x205907FB,
5602 + 0x00404000,
5603 + 0x075920FE,
5604 + 0x056F0CFF,
5605 + 0x027B0300,
5606 + },
5607 + {
5608 + 0x00800000,
5609 + 0x0D7CF8FF,
5610 + 0x1E70F5FE,
5611 + 0x335FF5FB,
5612 + 0xF7404000,
5613 + 0xF55F33FE,
5614 + 0xF5701EFF,
5615 + 0xF87C0D00,
5616 + },
5617 + };
5618 +
5619 + /* Coefficients for horizontal and vertical down-sampling */
5620 + static const u32 coef_hvdown[2][8] = {
5621 + {
5622 + 0x24382400,
5623 + 0x28391F04,
5624 + 0x2D381B08,
5625 + 0x3237170C,
5626 + 0x123737F7,
5627 + 0x173732F9,
5628 + 0x1B382DFB,
5629 + 0x1F3928FE,
5630 + },
5631 + {
5632 + 0x24382400,
5633 + 0x28371F04,
5634 + 0x2C361B08,
5635 + 0x3035160C,
5636 + 0x113433F7,
5637 + 0x163530F9,
5638 + 0x1B362CFB,
5639 + 0x1F3728FE,
5640 + },
5641 + };
5642 +
5643 + /* Coefficients for vertical up-sampling */
5644 + static const u32 coef_vup[8] = {
5645 + 0x00000000,
5646 + 0x0000FF00,
5647 + 0x0000FEFF,
5648 + 0x0000FBFE,
5649 + 0x000000F7,
5650 + 0x0000FEFB,
5651 + 0x0000FFFE,
5652 + 0x000000FF,
5653 + };
5654 +
5655 +
5656 + /* Coefficients for vertical down-sampling */
5657 + static const u32 coef_vdown[8] = {
5658 + 0x00000000,
5659 + 0x000004FE,
5660 + 0x000008FB,
5661 + 0x00000CF9,
5662 + 0x0000F711,
5663 + 0x0000F90C,
5664 + 0x0000FB08,
5665 + 0x0000FE04,
5666 + };
5667 +
5668 + const u32 *h_coef;
5669 + const u32 *hv_coef;
5670 + const u32 *hv_coef_mod;
5671 + const u32 *v_coef;
5672 + int i;
5673 +
5674 + if (hscaleup)
5675 + h_coef = coef_hup;
5676 + else
5677 + h_coef = coef_hdown;
5678 +
5679 + if (vscaleup) {
5680 + hv_coef = coef_hvup[five_taps];
5681 + v_coef = coef_vup;
5682 +
5683 + if (hscaleup)
5684 + hv_coef_mod = NULL;
5685 + else
5686 + hv_coef_mod = coef_hvdown[five_taps];
5687 + } else {
5688 + hv_coef = coef_hvdown[five_taps];
5689 + v_coef = coef_vdown;
5690 +
5691 + if (hscaleup)
5692 + hv_coef_mod = coef_hvup[five_taps];
5693 + else
5694 + hv_coef_mod = NULL;
5695 + }
5696 +
5697 + for (i = 0; i < 8; i++) {
5698 + u32 h, hv;
5699 +
5700 + h = h_coef[i];
5701 +
5702 + hv = hv_coef[i];
5703 +
5704 + if (hv_coef_mod) {
5705 + hv &= 0xffffff00;
5706 + hv |= (hv_coef_mod[i] & 0xff);
5707 + }
5708 +
5709 + _dispc_write_firh_reg(plane, i, h);
5710 + _dispc_write_firhv_reg(plane, i, hv);
5711 + }
5712 +
5713 + if (!five_taps)
5714 + return;
5715 +
5716 + for (i = 0; i < 8; i++) {
5717 + u32 v;
5718 + v = v_coef[i];
5719 + _dispc_write_firv_reg(plane, i, v);
5720 + }
5721 +}
5722 +
5723 +static void _dispc_setup_color_conv_coef(void)
5724 +{
5725 + const struct color_conv_coef {
5726 + int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb;
5727 + int full_range;
5728 + } ctbl_bt601_5 = {
5729 + 298, 409, 0, 298, -208, -100, 298, 0, 517, 0,
5730 + };
5731 +
5732 + const struct color_conv_coef *ct;
5733 +
5734 +#define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0))
5735 +
5736 + ct = &ctbl_bt601_5;
5737 +
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));
5743 +
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));
5749 +
5750 +#undef CVAL
5751 +
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);
5754 +}
5755 +
5756 +
5757 +static void _dispc_set_plane_ba0(enum omap_plane plane, u32 paddr)
5758 +{
5759 + const struct dispc_reg ba0_reg[] = { DISPC_GFX_BA0,
5760 + DISPC_VID_BA0(0),
5761 + DISPC_VID_BA0(1) };
5762 +
5763 + dispc_write_reg(ba0_reg[plane], paddr);
5764 +}
5765 +
5766 +static void _dispc_set_plane_ba1(enum omap_plane plane, u32 paddr)
5767 +{
5768 + const struct dispc_reg ba1_reg[] = { DISPC_GFX_BA1,
5769 + DISPC_VID_BA1(0),
5770 + DISPC_VID_BA1(1) };
5771 +
5772 + dispc_write_reg(ba1_reg[plane], paddr);
5773 +}
5774 +
5775 +static void _dispc_set_plane_pos(enum omap_plane plane, int x, int y)
5776 +{
5777 + const struct dispc_reg pos_reg[] = { DISPC_GFX_POSITION,
5778 + DISPC_VID_POSITION(0),
5779 + DISPC_VID_POSITION(1) };
5780 +
5781 + u32 val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0);
5782 + dispc_write_reg(pos_reg[plane], val);
5783 +}
5784 +
5785 +static void _dispc_set_pic_size(enum omap_plane plane, int width, int height)
5786 +{
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);
5792 +}
5793 +
5794 +static void _dispc_set_vid_size(enum omap_plane plane, int width, int height)
5795 +{
5796 + u32 val;
5797 + const struct dispc_reg vsi_reg[] = { DISPC_VID_SIZE(0),
5798 + DISPC_VID_SIZE(1) };
5799 +
5800 + BUG_ON(plane == OMAP_DSS_GFX);
5801 +
5802 + val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
5803 + dispc_write_reg(vsi_reg[plane-1], val);
5804 +}
5805 +
5806 +static void _dispc_setup_global_alpha(enum omap_plane plane, u8 global_alpha)
5807 +{
5808 +
5809 + BUG_ON(plane == OMAP_DSS_VIDEO1);
5810 +
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);
5815 +}
5816 +
5817 +static void _dispc_set_pix_inc(enum omap_plane plane, s32 inc)
5818 +{
5819 + const struct dispc_reg ri_reg[] = { DISPC_GFX_PIXEL_INC,
5820 + DISPC_VID_PIXEL_INC(0),
5821 + DISPC_VID_PIXEL_INC(1) };
5822 +
5823 + dispc_write_reg(ri_reg[plane], inc);
5824 +}
5825 +
5826 +static void _dispc_set_row_inc(enum omap_plane plane, s32 inc)
5827 +{
5828 + const struct dispc_reg ri_reg[] = { DISPC_GFX_ROW_INC,
5829 + DISPC_VID_ROW_INC(0),
5830 + DISPC_VID_ROW_INC(1) };
5831 +
5832 + dispc_write_reg(ri_reg[plane], inc);
5833 +}
5834 +
5835 +static void _dispc_set_color_mode(enum omap_plane plane,
5836 + enum omap_color_mode color_mode)
5837 +{
5838 + u32 m = 0;
5839 +
5840 + switch (color_mode) {
5841 + case OMAP_DSS_COLOR_CLUT1:
5842 + m = 0x0; break;
5843 + case OMAP_DSS_COLOR_CLUT2:
5844 + m = 0x1; break;
5845 + case OMAP_DSS_COLOR_CLUT4:
5846 + m = 0x2; break;
5847 + case OMAP_DSS_COLOR_CLUT8:
5848 + m = 0x3; break;
5849 + case OMAP_DSS_COLOR_RGB12U:
5850 + m = 0x4; break;
5851 + case OMAP_DSS_COLOR_ARGB16:
5852 + m = 0x5; break;
5853 + case OMAP_DSS_COLOR_RGB16:
5854 + m = 0x6; break;
5855 + case OMAP_DSS_COLOR_RGB24U:
5856 + m = 0x8; break;
5857 + case OMAP_DSS_COLOR_RGB24P:
5858 + m = 0x9; break;
5859 + case OMAP_DSS_COLOR_YUV2:
5860 + m = 0xa; break;
5861 + case OMAP_DSS_COLOR_UYVY:
5862 + m = 0xb; break;
5863 + case OMAP_DSS_COLOR_ARGB32:
5864 + m = 0xc; break;
5865 + case OMAP_DSS_COLOR_RGBA32:
5866 + m = 0xd; break;
5867 + case OMAP_DSS_COLOR_RGBX32:
5868 + m = 0xe; break;
5869 + default:
5870 + BUG(); break;
5871 + }
5872 +
5873 + REG_FLD_MOD(dispc_reg_att[plane], m, 4, 1);
5874 +}
5875 +
5876 +static void _dispc_set_channel_out(enum omap_plane plane,
5877 + enum omap_channel channel)
5878 +{
5879 + int shift;
5880 + u32 val;
5881 +
5882 + switch (plane) {
5883 + case OMAP_DSS_GFX:
5884 + shift = 8;
5885 + break;
5886 + case OMAP_DSS_VIDEO1:
5887 + case OMAP_DSS_VIDEO2:
5888 + shift = 16;
5889 + break;
5890 + default:
5891 + BUG();
5892 + return;
5893 + }
5894 +
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);
5898 +}
5899 +
5900 +void dispc_set_burst_size(enum omap_plane plane,
5901 + enum omap_burst_size burst_size)
5902 +{
5903 + int shift;
5904 + u32 val;
5905 +
5906 + enable_clocks(1);
5907 +
5908 + switch (plane) {
5909 + case OMAP_DSS_GFX:
5910 + shift = 6;
5911 + break;
5912 + case OMAP_DSS_VIDEO1:
5913 + case OMAP_DSS_VIDEO2:
5914 + shift = 14;
5915 + break;
5916 + default:
5917 + BUG();
5918 + return;
5919 + }
5920 +
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);
5924 +
5925 + enable_clocks(0);
5926 +}
5927 +
5928 +static void _dispc_set_vid_color_conv(enum omap_plane plane, bool enable)
5929 +{
5930 + u32 val;
5931 +
5932 + BUG_ON(plane == OMAP_DSS_GFX);
5933 +
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);
5937 +}
5938 +
5939 +void dispc_enable_replication(enum omap_plane plane, bool enable)
5940 +{
5941 + int bit;
5942 +
5943 + if (plane == OMAP_DSS_GFX)
5944 + bit = 5;
5945 + else
5946 + bit = 10;
5947 +
5948 + enable_clocks(1);
5949 + REG_FLD_MOD(dispc_reg_att[plane], enable, bit, bit);
5950 + enable_clocks(0);
5951 +}
5952 +
5953 +void dispc_set_lcd_size(u16 width, u16 height)
5954 +{
5955 + u32 val;
5956 + BUG_ON((width > (1 << 11)) || (height > (1 << 11)));
5957 + val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
5958 + enable_clocks(1);
5959 + dispc_write_reg(DISPC_SIZE_LCD, val);
5960 + enable_clocks(0);
5961 +}
5962 +
5963 +void dispc_set_digit_size(u16 width, u16 height)
5964 +{
5965 + u32 val;
5966 + BUG_ON((width > (1 << 11)) || (height > (1 << 11)));
5967 + val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
5968 + enable_clocks(1);
5969 + dispc_write_reg(DISPC_SIZE_DIG, val);
5970 + enable_clocks(0);
5971 +}
5972 +
5973 +static void dispc_read_plane_fifo_sizes(void)
5974 +{
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) };
5978 + u32 size;
5979 + int plane;
5980 +
5981 + enable_clocks(1);
5982 +
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);
5988 + else
5989 + BUG();
5990 +
5991 + dispc.fifo_size[plane] = size;
5992 + }
5993 +
5994 + enable_clocks(0);
5995 +}
5996 +
5997 +u32 dispc_get_plane_fifo_size(enum omap_plane plane)
5998 +{
5999 + return dispc.fifo_size[plane];
6000 +}
6001 +
6002 +void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high)
6003 +{
6004 + const struct dispc_reg ftrs_reg[] = { DISPC_GFX_FIFO_THRESHOLD,
6005 + DISPC_VID_FIFO_THRESHOLD(0),
6006 + DISPC_VID_FIFO_THRESHOLD(1) };
6007 + enable_clocks(1);
6008 +
6009 + DSSDBG("fifo(%d) low/high old %u/%u, new %u/%u\n",
6010 + plane,
6011 + REG_GET(ftrs_reg[plane], 11, 0),
6012 + REG_GET(ftrs_reg[plane], 27, 16),
6013 + low, high);
6014 +
6015 + if (cpu_is_omap24xx())
6016 + dispc_write_reg(ftrs_reg[plane],
6017 + FLD_VAL(high, 24, 16) | FLD_VAL(low, 8, 0));
6018 + else
6019 + dispc_write_reg(ftrs_reg[plane],
6020 + FLD_VAL(high, 27, 16) | FLD_VAL(low, 11, 0));
6021 +
6022 + enable_clocks(0);
6023 +}
6024 +
6025 +void dispc_enable_fifomerge(bool enable)
6026 +{
6027 + enable_clocks(1);
6028 +
6029 + DSSDBG("FIFO merge %s\n", enable ? "enabled" : "disabled");
6030 + REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 14, 14);
6031 +
6032 + enable_clocks(0);
6033 +}
6034 +
6035 +static void _dispc_set_fir(enum omap_plane plane, int hinc, int vinc)
6036 +{
6037 + u32 val;
6038 + const struct dispc_reg fir_reg[] = { DISPC_VID_FIR(0),
6039 + DISPC_VID_FIR(1) };
6040 +
6041 + BUG_ON(plane == OMAP_DSS_GFX);
6042 +
6043 + if (cpu_is_omap24xx())
6044 + val = FLD_VAL(vinc, 27, 16) | FLD_VAL(hinc, 11, 0);
6045 + else
6046 + val = FLD_VAL(vinc, 28, 16) | FLD_VAL(hinc, 12, 0);
6047 + dispc_write_reg(fir_reg[plane-1], val);
6048 +}
6049 +
6050 +static void _dispc_set_vid_accu0(enum omap_plane plane, int haccu, int vaccu)
6051 +{
6052 + u32 val;
6053 + const struct dispc_reg ac0_reg[] = { DISPC_VID_ACCU0(0),
6054 + DISPC_VID_ACCU0(1) };
6055 +
6056 + BUG_ON(plane == OMAP_DSS_GFX);
6057 +
6058 + val = FLD_VAL(vaccu, 25, 16) | FLD_VAL(haccu, 9, 0);
6059 + dispc_write_reg(ac0_reg[plane-1], val);
6060 +}
6061 +
6062 +static void _dispc_set_vid_accu1(enum omap_plane plane, int haccu, int vaccu)
6063 +{
6064 + u32 val;
6065 + const struct dispc_reg ac1_reg[] = { DISPC_VID_ACCU1(0),
6066 + DISPC_VID_ACCU1(1) };
6067 +
6068 + BUG_ON(plane == OMAP_DSS_GFX);
6069 +
6070 + val = FLD_VAL(vaccu, 25, 16) | FLD_VAL(haccu, 9, 0);
6071 + dispc_write_reg(ac1_reg[plane-1], val);
6072 +}
6073 +
6074 +
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,
6079 + bool fieldmode)
6080 +{
6081 + int fir_hinc;
6082 + int fir_vinc;
6083 + int hscaleup, vscaleup;
6084 + int accu0 = 0;
6085 + int accu1 = 0;
6086 + u32 l;
6087 +
6088 + BUG_ON(plane == OMAP_DSS_GFX);
6089 +
6090 + hscaleup = orig_width <= out_width;
6091 + vscaleup = orig_height <= out_height;
6092 +
6093 + _dispc_set_scale_coef(plane, hscaleup, vscaleup, five_taps);
6094 +
6095 + if (!orig_width || orig_width == out_width)
6096 + fir_hinc = 0;
6097 + else
6098 + fir_hinc = 1024 * orig_width / out_width;
6099 +
6100 + if (!orig_height || orig_height == out_height)
6101 + fir_vinc = 0;
6102 + else
6103 + fir_vinc = 1024 * orig_height / out_height;
6104 +
6105 + _dispc_set_fir(plane, fir_hinc, fir_vinc);
6106 +
6107 + l = dispc_read_reg(dispc_reg_att[plane]);
6108 + l &= ~((0x0f << 5) | (0x3 << 21));
6109 +
6110 + l |= fir_hinc ? (1 << 5) : 0;
6111 + l |= fir_vinc ? (1 << 6) : 0;
6112 +
6113 + l |= hscaleup ? 0 : (1 << 7);
6114 + l |= vscaleup ? 0 : (1 << 8);
6115 +
6116 + l |= five_taps ? (1 << 21) : 0;
6117 + l |= five_taps ? (1 << 22) : 0;
6118 +
6119 + dispc_write_reg(dispc_reg_att[plane], l);
6120 +
6121 + /*
6122 + * field 0 = even field = bottom field
6123 + * field 1 = odd field = top field
6124 + */
6125 + if (ilace && !fieldmode) {
6126 + accu1 = 0;
6127 + accu0 = (fir_vinc / 2) & 0x3ff;
6128 + if (accu0 >= 1024/2) {
6129 + accu1 = 1024/2;
6130 + accu0 -= accu1;
6131 + }
6132 + }
6133 +
6134 + _dispc_set_vid_accu0(plane, 0, accu0);
6135 + _dispc_set_vid_accu1(plane, 0, accu1);
6136 +}
6137 +
6138 +static void _dispc_set_rotation_attrs(enum omap_plane plane, u8 rotation,
6139 + bool mirroring, enum omap_color_mode color_mode)
6140 +{
6141 + if (color_mode == OMAP_DSS_COLOR_YUV2 ||
6142 + color_mode == OMAP_DSS_COLOR_UYVY) {
6143 + int vidrot = 0;
6144 +
6145 + if (mirroring) {
6146 + switch (rotation) {
6147 + case 0:
6148 + vidrot = 2;
6149 + break;
6150 + case 1:
6151 + vidrot = 1;
6152 + break;
6153 + case 2:
6154 + vidrot = 0;
6155 + break;
6156 + case 3:
6157 + vidrot = 3;
6158 + break;
6159 + }
6160 + } else {
6161 + switch (rotation) {
6162 + case 0:
6163 + vidrot = 0;
6164 + break;
6165 + case 1:
6166 + vidrot = 1;
6167 + break;
6168 + case 2:
6169 + vidrot = 2;
6170 + break;
6171 + case 3:
6172 + vidrot = 3;
6173 + break;
6174 + }
6175 + }
6176 +
6177 + REG_FLD_MOD(dispc_reg_att[plane], vidrot, 13, 12);
6178 +
6179 + if (rotation == 1 || rotation == 3)
6180 + REG_FLD_MOD(dispc_reg_att[plane], 0x1, 18, 18);
6181 + else
6182 + REG_FLD_MOD(dispc_reg_att[plane], 0x0, 18, 18);
6183 + } else {
6184 + REG_FLD_MOD(dispc_reg_att[plane], 0, 13, 12);
6185 + REG_FLD_MOD(dispc_reg_att[plane], 0, 18, 18);
6186 + }
6187 +}
6188 +
6189 +static s32 pixinc(int pixels, u8 ps)
6190 +{
6191 + if (pixels == 1)
6192 + return 1;
6193 + else if (pixels > 1)
6194 + return 1 + (pixels - 1) * ps;
6195 + else if (pixels < 0)
6196 + return 1 - (-pixels + 1) * ps;
6197 + else
6198 + BUG();
6199 +}
6200 +
6201 +static void calc_vrfb_rotation_offset(u8 rotation, bool mirror,
6202 + u16 screen_width,
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)
6208 +{
6209 + u8 ps;
6210 +
6211 + switch (color_mode) {
6212 + case OMAP_DSS_COLOR_RGB16:
6213 + case OMAP_DSS_COLOR_ARGB16:
6214 + ps = 2;
6215 + break;
6216 +
6217 + case OMAP_DSS_COLOR_RGB24P:
6218 + ps = 3;
6219 + break;
6220 +
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:
6227 + ps = 4;
6228 + break;
6229 +
6230 + default:
6231 + BUG();
6232 + return;
6233 + }
6234 +
6235 + DSSDBG("calc_rot(%d): scrw %d, %dx%d\n", rotation, screen_width,
6236 + width, height);
6237 +
6238 + /*
6239 + * field 0 = even field = bottom field
6240 + * field 1 = odd field = top field
6241 + */
6242 + switch (rotation + mirror * 4) {
6243 + case 0:
6244 + case 2:
6245 + /*
6246 + * If the pixel format is YUV or UYVY divide the width
6247 + * of the image by 2 for 0 and 180 degree rotation.
6248 + */
6249 + if (color_mode == OMAP_DSS_COLOR_YUV2 ||
6250 + color_mode == OMAP_DSS_COLOR_UYVY)
6251 + width = width >> 1;
6252 + case 1:
6253 + case 3:
6254 + *offset1 = 0;
6255 + if (field_offset)
6256 + *offset0 = field_offset * screen_width * ps;
6257 + else
6258 + *offset0 = 0;
6259 +
6260 + *row_inc = pixinc(1 + (screen_width - width) +
6261 + (fieldmode ? screen_width : 0),
6262 + ps);
6263 + *pix_inc = pixinc(1, ps);
6264 + break;
6265 +
6266 + case 4:
6267 + case 6:
6268 + /* If the pixel format is YUV or UYVY divide the width
6269 + * of the image by 2 for 0 degree and 180 degree
6270 + */
6271 + if (color_mode == OMAP_DSS_COLOR_YUV2 ||
6272 + color_mode == OMAP_DSS_COLOR_UYVY)
6273 + width = width >> 1;
6274 + case 5:
6275 + case 7:
6276 + *offset1 = 0;
6277 + if (field_offset)
6278 + *offset0 = field_offset * screen_width * ps;
6279 + else
6280 + *offset0 = 0;
6281 + *row_inc = pixinc(1 - (screen_width + width) -
6282 + (fieldmode ? screen_width : 0),
6283 + ps);
6284 + *pix_inc = pixinc(1, ps);
6285 + break;
6286 +
6287 + default:
6288 + BUG();
6289 + }
6290 +}
6291 +
6292 +static void calc_dma_rotation_offset(u8 rotation, bool mirror,
6293 + u16 screen_width,
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)
6299 +{
6300 + u8 ps;
6301 + u16 fbw, fbh;
6302 +
6303 + switch (color_mode) {
6304 + case OMAP_DSS_COLOR_RGB16:
6305 + case OMAP_DSS_COLOR_ARGB16:
6306 + ps = 2;
6307 + break;
6308 +
6309 + case OMAP_DSS_COLOR_RGB24P:
6310 + ps = 3;
6311 + break;
6312 +
6313 + case OMAP_DSS_COLOR_RGB24U:
6314 + case OMAP_DSS_COLOR_ARGB32:
6315 + case OMAP_DSS_COLOR_RGBA32:
6316 + case OMAP_DSS_COLOR_RGBX32:
6317 + ps = 4;
6318 + break;
6319 +
6320 + case OMAP_DSS_COLOR_YUV2:
6321 + case OMAP_DSS_COLOR_UYVY:
6322 + ps = 2;
6323 + break;
6324 + default:
6325 + BUG();
6326 + return;
6327 + }
6328 +
6329 + DSSDBG("calc_rot(%d): scrw %d, %dx%d\n", rotation, screen_width,
6330 + width, height);
6331 +
6332 + /* width & height are overlay sizes, convert to fb sizes */
6333 +
6334 + if (rotation == 0 || rotation == 2) {
6335 + fbw = width;
6336 + fbh = height;
6337 + } else {
6338 + fbw = height;
6339 + fbh = width;
6340 + }
6341 +
6342 + /*
6343 + * field 0 = even field = bottom field
6344 + * field 1 = odd field = top field
6345 + */
6346 + switch (rotation + mirror * 4) {
6347 + case 0:
6348 + *offset1 = 0;
6349 + if (field_offset)
6350 + *offset0 = *offset1 + field_offset * screen_width * ps;
6351 + else
6352 + *offset0 = *offset1;
6353 + *row_inc = pixinc(1 + (screen_width - fbw) +
6354 + (fieldmode ? screen_width : 0),
6355 + ps);
6356 + *pix_inc = pixinc(1, ps);
6357 + break;
6358 + case 1:
6359 + *offset1 = screen_width * (fbh - 1) * ps;
6360 + if (field_offset)
6361 + *offset0 = *offset1 + field_offset * ps;
6362 + else
6363 + *offset0 = *offset1;
6364 + *row_inc = pixinc(screen_width * (fbh - 1) + 1 +
6365 + (fieldmode ? 1 : 0), ps);
6366 + *pix_inc = pixinc(-screen_width, ps);
6367 + break;
6368 + case 2:
6369 + *offset1 = (screen_width * (fbh - 1) + fbw - 1) * ps;
6370 + if (field_offset)
6371 + *offset0 = *offset1 - field_offset * screen_width * ps;
6372 + else
6373 + *offset0 = *offset1;
6374 + *row_inc = pixinc(-1 -
6375 + (screen_width - fbw) -
6376 + (fieldmode ? screen_width : 0),
6377 + ps);
6378 + *pix_inc = pixinc(-1, ps);
6379 + break;
6380 + case 3:
6381 + *offset1 = (fbw - 1) * ps;
6382 + if (field_offset)
6383 + *offset0 = *offset1 - field_offset * ps;
6384 + else
6385 + *offset0 = *offset1;
6386 + *row_inc = pixinc(-screen_width * (fbh - 1) - 1 -
6387 + (fieldmode ? 1 : 0), ps);
6388 + *pix_inc = pixinc(screen_width, ps);
6389 + break;
6390 +
6391 + /* mirroring */
6392 + case 0 + 4:
6393 + *offset1 = (fbw - 1) * ps;
6394 + if (field_offset)
6395 + *offset0 = *offset1 + field_offset * screen_width * ps;
6396 + else
6397 + *offset0 = *offset1;
6398 + *row_inc = pixinc(screen_width * 2 - 1 +
6399 + (fieldmode ? screen_width : 0),
6400 + ps);
6401 + *pix_inc = pixinc(-1, ps);
6402 + break;
6403 +
6404 + case 1 + 4:
6405 + *offset1 = 0;
6406 + if (field_offset)
6407 + *offset0 = *offset1 + field_offset * ps;
6408 + else
6409 + *offset0 = *offset1;
6410 + *row_inc = pixinc(-screen_width * (fbh - 1) + 1 +
6411 + (fieldmode ? 1 : 0),
6412 + ps);
6413 + *pix_inc = pixinc(screen_width, ps);
6414 + break;
6415 +
6416 + case 2 + 4:
6417 + *offset1 = screen_width * (fbh - 1) * ps;
6418 + if (field_offset)
6419 + *offset0 = *offset1 - field_offset * screen_width * ps;
6420 + else
6421 + *offset0 = *offset1;
6422 + *row_inc = pixinc(1 - screen_width * 2 -
6423 + (fieldmode ? screen_width : 0),
6424 + ps);
6425 + *pix_inc = pixinc(1, ps);
6426 + break;
6427 +
6428 + case 3 + 4:
6429 + *offset1 = (screen_width * (fbh - 1) + fbw - 1) * ps;
6430 + if (field_offset)
6431 + *offset0 = *offset1 - field_offset * ps;
6432 + else
6433 + *offset0 = *offset1;
6434 + *row_inc = pixinc(screen_width * (fbh - 1) - 1 -
6435 + (fieldmode ? 1 : 0),
6436 + ps);
6437 + *pix_inc = pixinc(-screen_width, ps);
6438 + break;
6439 +
6440 + default:
6441 + BUG();
6442 + }
6443 +}
6444 +
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)
6447 +{
6448 + u32 fclk = 0;
6449 + /* FIXME venc pclk? */
6450 + u64 tmp, pclk = dispc_pclk_rate();
6451 +
6452 + if (height > out_height) {
6453 + /* FIXME get real display PPL */
6454 + unsigned int ppl = 800;
6455 +
6456 + tmp = pclk * height * out_width;
6457 + do_div(tmp, 2 * out_height * ppl);
6458 + fclk = tmp;
6459 +
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);
6464 + }
6465 + }
6466 +
6467 + if (width > out_width) {
6468 + tmp = pclk * width;
6469 + do_div(tmp, out_width);
6470 + fclk = max(fclk, (u32) tmp);
6471 +
6472 + if (color_mode == OMAP_DSS_COLOR_RGB24U)
6473 + fclk <<= 1;
6474 + }
6475 +
6476 + return fclk;
6477 +}
6478 +
6479 +static unsigned long calc_fclk(u16 width, u16 height,
6480 + u16 out_width, u16 out_height)
6481 +{
6482 + unsigned int hf, vf;
6483 +
6484 + /*
6485 + * FIXME how to determine the 'A' factor
6486 + * for the no downscaling case ?
6487 + */
6488 +
6489 + if (width > 3 * out_width)
6490 + hf = 4;
6491 + else if (width > 2 * out_width)
6492 + hf = 3;
6493 + else if (width > out_width)
6494 + hf = 2;
6495 + else
6496 + hf = 1;
6497 +
6498 + if (height > out_height)
6499 + vf = 2;
6500 + else
6501 + vf = 1;
6502 +
6503 + /* FIXME venc pclk? */
6504 + return dispc_pclk_rate() * vf * hf;
6505 +}
6506 +
6507 +void dispc_set_channel_out(enum omap_plane plane, enum omap_channel channel_out)
6508 +{
6509 + enable_clocks(1);
6510 + _dispc_set_channel_out(plane, channel_out);
6511 + enable_clocks(0);
6512 +}
6513 +
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,
6520 + bool ilace,
6521 + enum omap_dss_rotation_type rotation_type,
6522 + u8 rotation, int mirror,
6523 + u8 global_alpha)
6524 +{
6525 + const int maxdownscale = cpu_is_omap34xx() ? 4 : 2;
6526 + bool five_taps = 0;
6527 + bool fieldmode = 0;
6528 + int cconv = 0;
6529 + unsigned offset0, offset1;
6530 + s32 row_inc;
6531 + s32 pix_inc;
6532 + u16 frame_height = height;
6533 + unsigned int field_offset = 0;
6534 +
6535 + if (paddr == 0)
6536 + return -EINVAL;
6537 +
6538 + if (ilace && height == out_height)
6539 + fieldmode = 1;
6540 +
6541 + if (ilace) {
6542 + if (fieldmode)
6543 + height /= 2;
6544 + pos_y /= 2;
6545 + out_height /= 2;
6546 +
6547 + DSSDBG("adjusting for ilace: height %d, pos_y %d, "
6548 + "out_height %d\n",
6549 + height, pos_y, out_height);
6550 + }
6551 +
6552 + if (plane == OMAP_DSS_GFX) {
6553 + if (width != out_width || height != out_height)
6554 + return -EINVAL;
6555 +
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:
6564 + break;
6565 +
6566 + default:
6567 + return -EINVAL;
6568 + }
6569 + } else {
6570 + /* video plane */
6571 +
6572 + unsigned long fclk = 0;
6573 +
6574 + if (out_width < width / maxdownscale ||
6575 + out_width > width * 8)
6576 + return -EINVAL;
6577 +
6578 + if (out_height < height / maxdownscale ||
6579 + out_height > height * 8)
6580 + return -EINVAL;
6581 +
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:
6587 + break;
6588 +
6589 + case OMAP_DSS_COLOR_ARGB16:
6590 + case OMAP_DSS_COLOR_ARGB32:
6591 + case OMAP_DSS_COLOR_RGBA32:
6592 + if (plane == OMAP_DSS_VIDEO1)
6593 + return -EINVAL;
6594 + break;
6595 +
6596 + case OMAP_DSS_COLOR_YUV2:
6597 + case OMAP_DSS_COLOR_UYVY:
6598 + cconv = 1;
6599 + break;
6600 +
6601 + default:
6602 + return -EINVAL;
6603 + }
6604 +
6605 + /* Must use 5-tap filter? */
6606 + five_taps = height > out_height * 2;
6607 +
6608 + if (!five_taps) {
6609 + fclk = calc_fclk(width, height,
6610 + out_width, out_height);
6611 +
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())
6615 + five_taps = true;
6616 + }
6617 +
6618 + if (width > (2048 >> five_taps))
6619 + return -EINVAL;
6620 +
6621 + if (five_taps)
6622 + fclk = calc_fclk_five_taps(width, height,
6623 + out_width, out_height, color_mode);
6624 +
6625 + DSSDBG("required fclk rate = %lu Hz\n", fclk);
6626 + DSSDBG("current fclk rate = %lu Hz\n", dispc_fclk_rate());
6627 +
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());
6633 + return -EINVAL;
6634 + }
6635 + }
6636 +
6637 + if (ilace && !fieldmode) {
6638 + /*
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
6643 + * bottom field.
6644 + */
6645 + if (!height || height == out_height)
6646 + field_offset = 0;
6647 + else
6648 + field_offset = height / out_height / 2;
6649 + }
6650 +
6651 + /* Fields are independent but interleaved in memory. */
6652 + if (fieldmode)
6653 + field_offset = 1;
6654 +
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);
6660 + else
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);
6665 +
6666 + DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n",
6667 + offset0, offset1, row_inc, pix_inc);
6668 +
6669 + _dispc_set_color_mode(plane, color_mode);
6670 +
6671 + _dispc_set_plane_ba0(plane, paddr + offset0);
6672 + _dispc_set_plane_ba1(plane, paddr + offset1);
6673 +
6674 + _dispc_set_row_inc(plane, row_inc);
6675 + _dispc_set_pix_inc(plane, pix_inc);
6676 +
6677 + DSSDBG("%d,%d %dx%d -> %dx%d\n", pos_x, pos_y, width, height,
6678 + out_width, out_height);
6679 +
6680 + _dispc_set_plane_pos(plane, pos_x, pos_y);
6681 +
6682 + _dispc_set_pic_size(plane, width, height);
6683 +
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);
6690 + }
6691 +
6692 + _dispc_set_rotation_attrs(plane, rotation, mirror, color_mode);
6693 +
6694 + if (plane != OMAP_DSS_VIDEO1)
6695 + _dispc_setup_global_alpha(plane, global_alpha);
6696 +
6697 + return 0;
6698 +}
6699 +
6700 +static void _dispc_enable_plane(enum omap_plane plane, bool enable)
6701 +{
6702 + REG_FLD_MOD(dispc_reg_att[plane], enable ? 1 : 0, 0, 0);
6703 +}
6704 +
6705 +static void dispc_disable_isr(void *data, u32 mask)
6706 +{
6707 + struct completion *compl = data;
6708 + complete(compl);
6709 +}
6710 +
6711 +static void _enable_lcd_out(bool enable)
6712 +{
6713 + REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 0, 0);
6714 +}
6715 +
6716 +void dispc_enable_lcd_out(bool enable)
6717 +{
6718 + struct completion frame_done_completion;
6719 + bool is_on;
6720 + int r;
6721 +
6722 + enable_clocks(1);
6723 +
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);
6728 +
6729 + if (!enable && is_on) {
6730 + init_completion(&frame_done_completion);
6731 +
6732 + r = omap_dispc_register_isr(dispc_disable_isr,
6733 + &frame_done_completion,
6734 + DISPC_IRQ_FRAMEDONE);
6735 +
6736 + if (r)
6737 + DSSERR("failed to register FRAMEDONE isr\n");
6738 + }
6739 +
6740 + _enable_lcd_out(enable);
6741 +
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");
6746 +
6747 + r = omap_dispc_unregister_isr(dispc_disable_isr,
6748 + &frame_done_completion,
6749 + DISPC_IRQ_FRAMEDONE);
6750 +
6751 + if (r)
6752 + DSSERR("failed to unregister FRAMEDONE isr\n");
6753 + }
6754 +
6755 + enable_clocks(0);
6756 +}
6757 +
6758 +static void _enable_digit_out(bool enable)
6759 +{
6760 + REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 1, 1);
6761 +}
6762 +
6763 +void dispc_enable_digit_out(bool enable)
6764 +{
6765 + struct completion frame_done_completion;
6766 + int r;
6767 +
6768 + enable_clocks(1);
6769 +
6770 + if (REG_GET(DISPC_CONTROL, 1, 1) == enable) {
6771 + enable_clocks(0);
6772 + return;
6773 + }
6774 +
6775 + if (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);
6783 + }
6784 +
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);
6790 +
6791 + r = omap_dispc_register_isr(dispc_disable_isr, &frame_done_completion,
6792 + DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD);
6793 + if (r)
6794 + DSSERR("failed to register EVSYNC isr\n");
6795 +
6796 + _enable_digit_out(enable);
6797 +
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");
6804 +
6805 + if (!wait_for_completion_timeout(&frame_done_completion,
6806 + msecs_to_jiffies(100)))
6807 + DSSERR("timeout waiting for EVSYNC\n");
6808 +
6809 + r = omap_dispc_unregister_isr(dispc_disable_isr,
6810 + &frame_done_completion,
6811 + DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD);
6812 + if (r)
6813 + DSSERR("failed to unregister EVSYNC isr\n");
6814 +
6815 + if (enable) {
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);
6822 + }
6823 +
6824 + enable_clocks(0);
6825 +}
6826 +
6827 +void dispc_lcd_enable_signal_polarity(bool act_high)
6828 +{
6829 + enable_clocks(1);
6830 + REG_FLD_MOD(DISPC_CONTROL, act_high ? 1 : 0, 29, 29);
6831 + enable_clocks(0);
6832 +}
6833 +
6834 +void dispc_lcd_enable_signal(bool enable)
6835 +{
6836 + enable_clocks(1);
6837 + REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 28, 28);
6838 + enable_clocks(0);
6839 +}
6840 +
6841 +void dispc_pck_free_enable(bool enable)
6842 +{
6843 + enable_clocks(1);
6844 + REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 27, 27);
6845 + enable_clocks(0);
6846 +}
6847 +
6848 +void dispc_enable_fifohandcheck(bool enable)
6849 +{
6850 + enable_clocks(1);
6851 + REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 16, 16);
6852 + enable_clocks(0);
6853 +}
6854 +
6855 +
6856 +void dispc_set_lcd_display_type(enum omap_lcd_display_type type)
6857 +{
6858 + int mode;
6859 +
6860 + switch (type) {
6861 + case OMAP_DSS_LCD_DISPLAY_STN:
6862 + mode = 0;
6863 + break;
6864 +
6865 + case OMAP_DSS_LCD_DISPLAY_TFT:
6866 + mode = 1;
6867 + break;
6868 +
6869 + default:
6870 + BUG();
6871 + return;
6872 + }
6873 +
6874 + enable_clocks(1);
6875 + REG_FLD_MOD(DISPC_CONTROL, mode, 3, 3);
6876 + enable_clocks(0);
6877 +}
6878 +
6879 +void dispc_set_loadmode(enum omap_dss_load_mode mode)
6880 +{
6881 + enable_clocks(1);
6882 + REG_FLD_MOD(DISPC_CONFIG, mode, 2, 1);
6883 + enable_clocks(0);
6884 +}
6885 +
6886 +
6887 +void dispc_set_default_color(enum omap_channel channel, u32 color)
6888 +{
6889 + const struct dispc_reg def_reg[] = { DISPC_DEFAULT_COLOR0,
6890 + DISPC_DEFAULT_COLOR1 };
6891 +
6892 + enable_clocks(1);
6893 + dispc_write_reg(def_reg[channel], color);
6894 + enable_clocks(0);
6895 +}
6896 +
6897 +u32 dispc_get_default_color(enum omap_channel channel)
6898 +{
6899 + const struct dispc_reg def_reg[] = { DISPC_DEFAULT_COLOR0,
6900 + DISPC_DEFAULT_COLOR1 };
6901 + u32 l;
6902 +
6903 + BUG_ON(channel != OMAP_DSS_CHANNEL_DIGIT &&
6904 + channel != OMAP_DSS_CHANNEL_LCD);
6905 +
6906 + enable_clocks(1);
6907 + l = dispc_read_reg(def_reg[channel]);
6908 + enable_clocks(0);
6909 +
6910 + return l;
6911 +}
6912 +
6913 +void dispc_set_trans_key(enum omap_channel ch,
6914 + enum omap_dss_trans_key_type type,
6915 + u32 trans_key)
6916 +{
6917 + const struct dispc_reg tr_reg[] = {
6918 + DISPC_TRANS_COLOR0, DISPC_TRANS_COLOR1 };
6919 +
6920 + enable_clocks(1);
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);
6925 +
6926 + dispc_write_reg(tr_reg[ch], trans_key);
6927 + enable_clocks(0);
6928 +}
6929 +
6930 +void dispc_get_trans_key(enum omap_channel ch,
6931 + enum omap_dss_trans_key_type *type,
6932 + u32 *trans_key)
6933 +{
6934 + const struct dispc_reg tr_reg[] = {
6935 + DISPC_TRANS_COLOR0, DISPC_TRANS_COLOR1 };
6936 +
6937 + enable_clocks(1);
6938 + if (type) {
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);
6943 + else
6944 + BUG();
6945 + }
6946 +
6947 + if (trans_key)
6948 + *trans_key = dispc_read_reg(tr_reg[ch]);
6949 + enable_clocks(0);
6950 +}
6951 +
6952 +void dispc_enable_trans_key(enum omap_channel ch, bool enable)
6953 +{
6954 + enable_clocks(1);
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);
6959 + enable_clocks(0);
6960 +}
6961 +void dispc_enable_alpha_blending(enum omap_channel ch, bool enable)
6962 +{
6963 + enable_clocks(1);
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);
6968 + enable_clocks(0);
6969 +}
6970 +bool dispc_alpha_blending_enabled(enum omap_channel ch)
6971 +{
6972 + bool enabled;
6973 +
6974 + enable_clocks(1);
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);
6979 + else
6980 + BUG();
6981 + enable_clocks(0);
6982 +
6983 + return enabled;
6984 +
6985 +}
6986 +
6987 +
6988 +bool dispc_trans_key_enabled(enum omap_channel ch)
6989 +{
6990 + bool enabled;
6991 +
6992 + enable_clocks(1);
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);
6997 + else
6998 + BUG();
6999 + enable_clocks(0);
7000 +
7001 + return enabled;
7002 +}
7003 +
7004 +
7005 +void dispc_set_tft_data_lines(u8 data_lines)
7006 +{
7007 + int code;
7008 +
7009 + switch (data_lines) {
7010 + case 12:
7011 + code = 0;
7012 + break;
7013 + case 16:
7014 + code = 1;
7015 + break;
7016 + case 18:
7017 + code = 2;
7018 + break;
7019 + case 24:
7020 + code = 3;
7021 + break;
7022 + default:
7023 + BUG();
7024 + return;
7025 + }
7026 +
7027 + enable_clocks(1);
7028 + REG_FLD_MOD(DISPC_CONTROL, code, 9, 8);
7029 + enable_clocks(0);
7030 +}
7031 +
7032 +void dispc_set_parallel_interface_mode(enum omap_parallel_interface_mode mode)
7033 +{
7034 + u32 l;
7035 + int stallmode;
7036 + int gpout0 = 1;
7037 + int gpout1;
7038 +
7039 + switch (mode) {
7040 + case OMAP_DSS_PARALLELMODE_BYPASS:
7041 + stallmode = 0;
7042 + gpout1 = 1;
7043 + break;
7044 +
7045 + case OMAP_DSS_PARALLELMODE_RFBI:
7046 + stallmode = 1;
7047 + gpout1 = 0;
7048 + break;
7049 +
7050 + case OMAP_DSS_PARALLELMODE_DSI:
7051 + stallmode = 1;
7052 + gpout1 = 1;
7053 + break;
7054 +
7055 + default:
7056 + BUG();
7057 + return;
7058 + }
7059 +
7060 + enable_clocks(1);
7061 +
7062 + l = dispc_read_reg(DISPC_CONTROL);
7063 +
7064 + l = FLD_MOD(l, stallmode, 11, 11);
7065 + l = FLD_MOD(l, gpout0, 15, 15);
7066 + l = FLD_MOD(l, gpout1, 16, 16);
7067 +
7068 + dispc_write_reg(DISPC_CONTROL, l);
7069 +
7070 + enable_clocks(0);
7071 +}
7072 +
7073 +static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp,
7074 + int vsw, int vfp, int vbp)
7075 +{
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)
7083 + return false;
7084 + } else {
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)
7091 + return false;
7092 + }
7093 +
7094 + return true;
7095 +}
7096 +
7097 +bool dispc_lcd_timings_ok(struct omap_video_timings *timings)
7098 +{
7099 + return _dispc_lcd_timings_ok(timings->hsw, timings->hfp,
7100 + timings->hbp, timings->vsw,
7101 + timings->vfp, timings->vbp);
7102 +}
7103 +
7104 +static void _dispc_set_lcd_timings(int hsw, int hfp, int hbp,
7105 + int vsw, int vfp, int vbp)
7106 +{
7107 + u32 timing_h, timing_v;
7108 +
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);
7112 +
7113 + timing_v = FLD_VAL(vsw-1, 5, 0) | FLD_VAL(vfp, 15, 8) |
7114 + FLD_VAL(vbp, 27, 20);
7115 + } else {
7116 + timing_h = FLD_VAL(hsw-1, 7, 0) | FLD_VAL(hfp-1, 19, 8) |
7117 + FLD_VAL(hbp-1, 31, 20);
7118 +
7119 + timing_v = FLD_VAL(vsw-1, 7, 0) | FLD_VAL(vfp, 19, 8) |
7120 + FLD_VAL(vbp, 31, 20);
7121 + }
7122 +
7123 + enable_clocks(1);
7124 + dispc_write_reg(DISPC_TIMING_H, timing_h);
7125 + dispc_write_reg(DISPC_TIMING_V, timing_v);
7126 + enable_clocks(0);
7127 +}
7128 +
7129 +/* change name to mode? */
7130 +void dispc_set_lcd_timings(struct omap_video_timings *timings)
7131 +{
7132 + unsigned xtot, ytot;
7133 + unsigned long ht, vt;
7134 +
7135 + if (!_dispc_lcd_timings_ok(timings->hsw, timings->hfp,
7136 + timings->hbp, timings->vsw,
7137 + timings->vfp, timings->vbp))
7138 + BUG();
7139 +
7140 + _dispc_set_lcd_timings(timings->hsw, timings->hfp, timings->hbp,
7141 + timings->vsw, timings->vfp, timings->vbp);
7142 +
7143 + dispc_set_lcd_size(timings->x_res, timings->y_res);
7144 +
7145 + xtot = timings->x_res + timings->hfp + timings->hsw + timings->hbp;
7146 + ytot = timings->y_res + timings->vfp + timings->vsw + timings->vbp;
7147 +
7148 + ht = (timings->pixel_clock * 1000) / xtot;
7149 + vt = (timings->pixel_clock * 1000) / xtot / ytot;
7150 +
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);
7156 +
7157 + DSSDBG("hsync %luHz, vsync %luHz\n", ht, vt);
7158 +}
7159 +
7160 +void dispc_set_lcd_divisor(u16 lck_div, u16 pck_div)
7161 +{
7162 + BUG_ON(lck_div < 1);
7163 + BUG_ON(pck_div < 2);
7164 +
7165 + enable_clocks(1);
7166 + dispc_write_reg(DISPC_DIVISOR,
7167 + FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0));
7168 + enable_clocks(0);
7169 +}
7170 +
7171 +static void dispc_get_lcd_divisor(int *lck_div, int *pck_div)
7172 +{
7173 + u32 l;
7174 + l = dispc_read_reg(DISPC_DIVISOR);
7175 + *lck_div = FLD_GET(l, 23, 16);
7176 + *pck_div = FLD_GET(l, 7, 0);
7177 +}
7178 +
7179 +unsigned long dispc_fclk_rate(void)
7180 +{
7181 + unsigned long r = 0;
7182 +
7183 + if (dss_get_dispc_clk_source() == 0)
7184 + r = dss_clk_get_rate(DSS_CLK_FCK1);
7185 + else
7186 +#ifdef CONFIG_OMAP2_DSS_DSI
7187 + r = dsi_get_dsi1_pll_rate();
7188 +#else
7189 + BUG();
7190 +#endif
7191 + return r;
7192 +}
7193 +
7194 +unsigned long dispc_lclk_rate(void)
7195 +{
7196 + int lcd;
7197 + unsigned long r;
7198 + u32 l;
7199 +
7200 + l = dispc_read_reg(DISPC_DIVISOR);
7201 +
7202 + lcd = FLD_GET(l, 23, 16);
7203 +
7204 + r = dispc_fclk_rate();
7205 +
7206 + return r / lcd;
7207 +}
7208 +
7209 +unsigned long dispc_pclk_rate(void)
7210 +{
7211 + int lcd, pcd;
7212 + unsigned long r;
7213 + u32 l;
7214 +
7215 + l = dispc_read_reg(DISPC_DIVISOR);
7216 +
7217 + lcd = FLD_GET(l, 23, 16);
7218 + pcd = FLD_GET(l, 7, 0);
7219 +
7220 + r = dispc_fclk_rate();
7221 +
7222 + return r / lcd / pcd;
7223 +}
7224 +
7225 +void dispc_dump_clocks(struct seq_file *s)
7226 +{
7227 + int lcd, pcd;
7228 +
7229 + enable_clocks(1);
7230 +
7231 + dispc_get_lcd_divisor(&lcd, &pcd);
7232 +
7233 + seq_printf(s, "- dispc -\n");
7234 +
7235 + seq_printf(s, "dispc fclk source = %s\n",
7236 + dss_get_dispc_clk_source() == 0 ?
7237 + "dss1_alwon_fclk" : "dsi1_pll_fclk");
7238 +
7239 + seq_printf(s, "pixel clk = %lu / %d / %d = %lu\n",
7240 + dispc_fclk_rate(),
7241 + lcd, pcd,
7242 + dispc_pclk_rate());
7243 +
7244 + enable_clocks(0);
7245 +}
7246 +
7247 +void dispc_dump_regs(struct seq_file *s)
7248 +{
7249 +#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dispc_read_reg(r))
7250 +
7251 + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
7252 +
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);
7274 +
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);
7286 +
7287 + DUMPREG(DISPC_DATA_CYCLE1);
7288 + DUMPREG(DISPC_DATA_CYCLE2);
7289 + DUMPREG(DISPC_DATA_CYCLE3);
7290 +
7291 + DUMPREG(DISPC_CPR_COEF_R);
7292 + DUMPREG(DISPC_CPR_COEF_G);
7293 + DUMPREG(DISPC_CPR_COEF_B);
7294 +
7295 + DUMPREG(DISPC_GFX_PRELOAD);
7296 +
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));
7310 +
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));
7324 +
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));
7354 +
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));
7384 +
7385 + DUMPREG(DISPC_VID_PRELOAD(0));
7386 + DUMPREG(DISPC_VID_PRELOAD(1));
7387 +
7388 + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
7389 +#undef DUMPREG
7390 +}
7391 +
7392 +static void _dispc_set_pol_freq(bool onoff, bool rf, bool ieo, bool ipc,
7393 + bool ihs, bool ivs, u8 acbi, u8 acb)
7394 +{
7395 + u32 l = 0;
7396 +
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);
7399 +
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);
7408 +
7409 + enable_clocks(1);
7410 + dispc_write_reg(DISPC_POL_FREQ, l);
7411 + enable_clocks(0);
7412 +}
7413 +
7414 +void dispc_set_pol_freq(enum omap_panel_config config, u8 acbi, u8 acb)
7415 +{
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,
7422 + acbi, acb);
7423 +}
7424 +
7425 +void find_lck_pck_divs(bool is_tft, unsigned long req_pck, unsigned long fck,
7426 + u16 *lck_div, u16 *pck_div)
7427 +{
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;
7432 +
7433 + best_pck = 0;
7434 + best_ld = 0;
7435 + best_pd = 0;
7436 +
7437 + for (cur_ld = 1; cur_ld <= 255; ++cur_ld) {
7438 + unsigned long lck = fck / cur_ld;
7439 +
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);
7444 +
7445 + if (best_pck == 0 || new_delta < old_delta) {
7446 + best_pck = pck;
7447 + best_ld = cur_ld;
7448 + best_pd = cur_pd;
7449 +
7450 + if (pck == req_pck)
7451 + goto found;
7452 + }
7453 +
7454 + if (pck < req_pck)
7455 + break;
7456 + }
7457 +
7458 + if (lck / pcd_min < req_pck)
7459 + break;
7460 + }
7461 +
7462 +found:
7463 + *lck_div = best_ld;
7464 + *pck_div = best_pd;
7465 +}
7466 +
7467 +int dispc_calc_clock_div(bool is_tft, unsigned long req_pck,
7468 + struct dispc_clock_info *cinfo)
7469 +{
7470 + unsigned long prate;
7471 + struct dispc_clock_info cur, best;
7472 + int match = 0;
7473 + int min_fck_per_pck;
7474 + unsigned long fck_rate = dss_clk_get_rate(DSS_CLK_FCK1);
7475 +
7476 + if (cpu_is_omap34xx())
7477 + prate = clk_get_rate(clk_get_parent(dispc.dpll4_m4_ck));
7478 + else
7479 + prate = 0;
7480 +
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;
7486 + return 0;
7487 + }
7488 +
7489 + min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
7490 +
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;
7497 + }
7498 +
7499 +retry:
7500 + memset(&cur, 0, sizeof(cur));
7501 + memset(&best, 0, sizeof(best));
7502 +
7503 + if (cpu_is_omap24xx()) {
7504 + /* XXX can we change the clock on omap2? */
7505 + cur.fck = dss_clk_get_rate(DSS_CLK_FCK1);
7506 + cur.fck_div = 1;
7507 +
7508 + match = 1;
7509 +
7510 + find_lck_pck_divs(is_tft, req_pck, cur.fck,
7511 + &cur.lck_div, &cur.pck_div);
7512 +
7513 + cur.lck = cur.fck / cur.lck_div;
7514 + cur.pck = cur.lck / cur.pck_div;
7515 +
7516 + best = cur;
7517 +
7518 + goto found;
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;
7522 +
7523 + if (cur.fck > DISPC_MAX_FCK)
7524 + continue;
7525 +
7526 + if (min_fck_per_pck &&
7527 + cur.fck < req_pck * min_fck_per_pck)
7528 + continue;
7529 +
7530 + match = 1;
7531 +
7532 + find_lck_pck_divs(is_tft, req_pck, cur.fck,
7533 + &cur.lck_div, &cur.pck_div);
7534 +
7535 + cur.lck = cur.fck / cur.lck_div;
7536 + cur.pck = cur.lck / cur.pck_div;
7537 +
7538 + if (abs(cur.pck - req_pck) < abs(best.pck - req_pck)) {
7539 + best = cur;
7540 +
7541 + if (cur.pck == req_pck)
7542 + goto found;
7543 + }
7544 + }
7545 + } else {
7546 + BUG();
7547 + }
7548 +
7549 +found:
7550 + if (!match) {
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;
7556 + goto retry;
7557 + }
7558 +
7559 + DSSERR("Could not find suitable clock settings.\n");
7560 +
7561 + return -EINVAL;
7562 + }
7563 +
7564 + if (cinfo)
7565 + *cinfo = best;
7566 +
7567 + dispc.cache_req_pck = req_pck;
7568 + dispc.cache_prate = prate;
7569 + dispc.cache_cinfo = best;
7570 +
7571 + return 0;
7572 +}
7573 +
7574 +int dispc_set_clock_div(struct dispc_clock_info *cinfo)
7575 +{
7576 + unsigned long prate;
7577 + int r;
7578 +
7579 + if (cpu_is_omap34xx()) {
7580 + prate = clk_get_rate(clk_get_parent(dispc.dpll4_m4_ck));
7581 + DSSDBG("dpll4_m4 = %ld\n", prate);
7582 + }
7583 +
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);
7587 +
7588 + if (cpu_is_omap34xx()) {
7589 + r = clk_set_rate(dispc.dpll4_m4_ck, prate / cinfo->fck_div);
7590 + if (r)
7591 + return r;
7592 + }
7593 +
7594 + dispc_set_lcd_divisor(cinfo->lck_div, cinfo->pck_div);
7595 +
7596 + return 0;
7597 +}
7598 +
7599 +int dispc_get_clock_div(struct dispc_clock_info *cinfo)
7600 +{
7601 + cinfo->fck = dss_clk_get_rate(DSS_CLK_FCK1);
7602 +
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);
7607 + } else {
7608 + cinfo->fck_div = 0;
7609 + }
7610 +
7611 + cinfo->lck_div = REG_GET(DISPC_DIVISOR, 23, 16);
7612 + cinfo->pck_div = REG_GET(DISPC_DIVISOR, 7, 0);
7613 +
7614 + cinfo->lck = cinfo->fck / cinfo->lck_div;
7615 + cinfo->pck = cinfo->lck / cinfo->pck_div;
7616 +
7617 + return 0;
7618 +}
7619 +
7620 +/* dispc.irq_lock has to be locked by the caller */
7621 +static void _omap_dispc_set_irqs(void)
7622 +{
7623 + u32 mask;
7624 + u32 old_mask;
7625 + int i;
7626 + struct omap_dispc_isr_data *isr_data;
7627 +
7628 + mask = dispc.irq_error_mask;
7629 +
7630 + for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
7631 + isr_data = &dispc.registered_isr[i];
7632 +
7633 + if (isr_data->isr == NULL)
7634 + continue;
7635 +
7636 + mask |= isr_data->mask;
7637 + }
7638 +
7639 + enable_clocks(1);
7640 +
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);
7644 +
7645 + dispc_write_reg(DISPC_IRQENABLE, mask);
7646 +
7647 + enable_clocks(0);
7648 +}
7649 +
7650 +int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
7651 +{
7652 + int i;
7653 + int ret;
7654 + unsigned long flags;
7655 + struct omap_dispc_isr_data *isr_data;
7656 +
7657 + if (isr == NULL)
7658 + return -EINVAL;
7659 +
7660 + spin_lock_irqsave(&dispc.irq_lock, flags);
7661 +
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) {
7667 + ret = -EINVAL;
7668 + goto err;
7669 + }
7670 + }
7671 +
7672 + isr_data = NULL;
7673 + ret = -EBUSY;
7674 +
7675 + for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
7676 + isr_data = &dispc.registered_isr[i];
7677 +
7678 + if (isr_data->isr != NULL)
7679 + continue;
7680 +
7681 + isr_data->isr = isr;
7682 + isr_data->arg = arg;
7683 + isr_data->mask = mask;
7684 + ret = 0;
7685 +
7686 + break;
7687 + }
7688 +
7689 + _omap_dispc_set_irqs();
7690 +
7691 + spin_unlock_irqrestore(&dispc.irq_lock, flags);
7692 +
7693 + return 0;
7694 +err:
7695 + spin_unlock_irqrestore(&dispc.irq_lock, flags);
7696 +
7697 + return ret;
7698 +}
7699 +EXPORT_SYMBOL(omap_dispc_register_isr);
7700 +
7701 +int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
7702 +{
7703 + int i;
7704 + unsigned long flags;
7705 + int ret = -EINVAL;
7706 + struct omap_dispc_isr_data *isr_data;
7707 +
7708 + spin_lock_irqsave(&dispc.irq_lock, flags);
7709 +
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)
7714 + continue;
7715 +
7716 + /* found the correct isr */
7717 +
7718 + isr_data->isr = NULL;
7719 + isr_data->arg = NULL;
7720 + isr_data->mask = 0;
7721 +
7722 + ret = 0;
7723 + break;
7724 + }
7725 +
7726 + if (ret == 0)
7727 + _omap_dispc_set_irqs();
7728 +
7729 + spin_unlock_irqrestore(&dispc.irq_lock, flags);
7730 +
7731 + return ret;
7732 +}
7733 +EXPORT_SYMBOL(omap_dispc_unregister_isr);
7734 +
7735 +#ifdef DEBUG
7736 +static void print_irq_status(u32 status)
7737 +{
7738 + if ((status & dispc.irq_error_mask) == 0)
7739 + return;
7740 +
7741 + printk(KERN_DEBUG "DISPC IRQ: 0x%x: ", status);
7742 +
7743 +#define PIS(x) \
7744 + if (status & DISPC_IRQ_##x) \
7745 + printk(#x " ");
7746 + PIS(GFX_FIFO_UNDERFLOW);
7747 + PIS(OCP_ERR);
7748 + PIS(VID1_FIFO_UNDERFLOW);
7749 + PIS(VID2_FIFO_UNDERFLOW);
7750 + PIS(SYNC_LOST);
7751 + PIS(SYNC_LOST_DIGIT);
7752 +#undef PIS
7753 +
7754 + printk("\n");
7755 +}
7756 +#endif
7757 +
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)
7763 +{
7764 + int i;
7765 + u32 irqstatus;
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];
7770 +
7771 + spin_lock(&dispc.irq_lock);
7772 +
7773 + irqstatus = dispc_read_reg(DISPC_IRQSTATUS);
7774 +
7775 +#ifdef DEBUG
7776 + if (dss_debug)
7777 + print_irq_status(irqstatus);
7778 +#endif
7779 + /* Ack the interrupt. Do it here before clocks are possibly turned
7780 + * off */
7781 + dispc_write_reg(DISPC_IRQSTATUS, irqstatus);
7782 +
7783 + /* make a copy and unlock, so that isrs can unregister
7784 + * themselves */
7785 + memcpy(registered_isr, dispc.registered_isr,
7786 + sizeof(registered_isr));
7787 +
7788 + spin_unlock(&dispc.irq_lock);
7789 +
7790 + for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
7791 + isr_data = &registered_isr[i];
7792 +
7793 + if (!isr_data->isr)
7794 + continue;
7795 +
7796 + if (isr_data->mask & irqstatus) {
7797 + isr_data->isr(isr_data->arg, irqstatus);
7798 + handledirqs |= isr_data->mask;
7799 + }
7800 + }
7801 +
7802 + spin_lock(&dispc.irq_lock);
7803 +
7804 + unhandled_errors = irqstatus & ~handledirqs & dispc.irq_error_mask;
7805 +
7806 + if (unhandled_errors) {
7807 + dispc.error_irqs |= unhandled_errors;
7808 +
7809 + dispc.irq_error_mask &= ~unhandled_errors;
7810 + _omap_dispc_set_irqs();
7811 +
7812 + schedule_work(&dispc.error_work);
7813 + }
7814 +
7815 + spin_unlock(&dispc.irq_lock);
7816 +}
7817 +
7818 +static void dispc_error_worker(struct work_struct *work)
7819 +{
7820 + int i;
7821 + u32 errors;
7822 + unsigned long flags;
7823 +
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);
7828 +
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);
7834 +
7835 + if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
7836 + continue;
7837 +
7838 + if (ovl->id == 0) {
7839 + dispc_enable_plane(ovl->id, 0);
7840 + dispc_go(ovl->manager->id);
7841 + mdelay(50);
7842 + break;
7843 + }
7844 + }
7845 + }
7846 +
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);
7852 +
7853 + if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
7854 + continue;
7855 +
7856 + if (ovl->id == 1) {
7857 + dispc_enable_plane(ovl->id, 0);
7858 + dispc_go(ovl->manager->id);
7859 + mdelay(50);
7860 + break;
7861 + }
7862 + }
7863 + }
7864 +
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);
7870 +
7871 + if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
7872 + continue;
7873 +
7874 + if (ovl->id == 2) {
7875 + dispc_enable_plane(ovl->id, 0);
7876 + dispc_go(ovl->manager->id);
7877 + mdelay(50);
7878 + break;
7879 + }
7880 + }
7881 + }
7882 +
7883 + if (errors & DISPC_IRQ_SYNC_LOST) {
7884 + struct omap_overlay_manager *manager = NULL;
7885 + bool enable = false;
7886 +
7887 + DSSERR("SYNC_LOST, disabling LCD\n");
7888 +
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);
7892 +
7893 + if (mgr->id == OMAP_DSS_CHANNEL_LCD) {
7894 + manager = mgr;
7895 + enable = mgr->device->state ==
7896 + OMAP_DSS_DISPLAY_ACTIVE;
7897 + mgr->device->disable(mgr->device);
7898 + break;
7899 + }
7900 + }
7901 +
7902 + if (manager) {
7903 + for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
7904 + struct omap_overlay *ovl;
7905 + ovl = omap_dss_get_overlay(i);
7906 +
7907 + if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
7908 + continue;
7909 +
7910 + if (ovl->id != 0 && ovl->manager == manager)
7911 + dispc_enable_plane(ovl->id, 0);
7912 + }
7913 +
7914 + dispc_go(manager->id);
7915 + mdelay(50);
7916 + if (enable)
7917 + manager->device->enable(manager->device);
7918 + }
7919 + }
7920 +
7921 + if (errors & DISPC_IRQ_SYNC_LOST_DIGIT) {
7922 + struct omap_overlay_manager *manager = NULL;
7923 + bool enable = false;
7924 +
7925 + DSSERR("SYNC_LOST_DIGIT, disabling TV\n");
7926 +
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);
7930 +
7931 + if (mgr->id == OMAP_DSS_CHANNEL_DIGIT) {
7932 + manager = mgr;
7933 + enable = mgr->device->state ==
7934 + OMAP_DSS_DISPLAY_ACTIVE;
7935 + mgr->device->disable(mgr->device);
7936 + break;
7937 + }
7938 + }
7939 +
7940 + if (manager) {
7941 + for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
7942 + struct omap_overlay *ovl;
7943 + ovl = omap_dss_get_overlay(i);
7944 +
7945 + if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
7946 + continue;
7947 +
7948 + if (ovl->id != 0 && ovl->manager == manager)
7949 + dispc_enable_plane(ovl->id, 0);
7950 + }
7951 +
7952 + dispc_go(manager->id);
7953 + mdelay(50);
7954 + if (enable)
7955 + manager->device->enable(manager->device);
7956 + }
7957 + }
7958 +
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);
7964 +
7965 + if (mgr->caps & OMAP_DSS_OVL_CAP_DISPC)
7966 + mgr->device->disable(mgr->device);
7967 + }
7968 + }
7969 +
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);
7974 +}
7975 +
7976 +int omap_dispc_wait_for_irq_timeout(u32 irqmask, unsigned long timeout)
7977 +{
7978 + void dispc_irq_wait_handler(void *data, u32 mask)
7979 + {
7980 + complete((struct completion *)data);
7981 + }
7982 +
7983 + int r;
7984 + DECLARE_COMPLETION_ONSTACK(completion);
7985 +
7986 + r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion,
7987 + irqmask);
7988 +
7989 + if (r)
7990 + return r;
7991 +
7992 + timeout = wait_for_completion_timeout(&completion, timeout);
7993 +
7994 + omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask);
7995 +
7996 + if (timeout == 0)
7997 + return -ETIMEDOUT;
7998 +
7999 + if (timeout == -ERESTARTSYS)
8000 + return -ERESTARTSYS;
8001 +
8002 + return 0;
8003 +}
8004 +
8005 +int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
8006 + unsigned long timeout)
8007 +{
8008 + void dispc_irq_wait_handler(void *data, u32 mask)
8009 + {
8010 + complete((struct completion *)data);
8011 + }
8012 +
8013 + int r;
8014 + DECLARE_COMPLETION_ONSTACK(completion);
8015 +
8016 + r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion,
8017 + irqmask);
8018 +
8019 + if (r)
8020 + return r;
8021 +
8022 + timeout = wait_for_completion_interruptible_timeout(&completion,
8023 + timeout);
8024 +
8025 + omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask);
8026 +
8027 + if (timeout == 0)
8028 + return -ETIMEDOUT;
8029 +
8030 + if (timeout == -ERESTARTSYS)
8031 + return -ERESTARTSYS;
8032 +
8033 + return 0;
8034 +}
8035 +
8036 +#ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC
8037 +void dispc_fake_vsync_irq(void)
8038 +{
8039 + u32 irqstatus = DISPC_IRQ_VSYNC;
8040 + int i;
8041 +
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];
8045 +
8046 + if (!isr_data->isr)
8047 + continue;
8048 +
8049 + if (isr_data->mask & irqstatus)
8050 + isr_data->isr(isr_data->arg, irqstatus);
8051 + }
8052 +}
8053 +#endif
8054 +
8055 +static void _omap_dispc_initialize_irq(void)
8056 +{
8057 + unsigned long flags;
8058 +
8059 + spin_lock_irqsave(&dispc.irq_lock, flags);
8060 +
8061 + memset(dispc.registered_isr, 0, sizeof(dispc.registered_isr));
8062 +
8063 + dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR;
8064 +
8065 + /* there's SYNC_LOST_DIGIT waiting after enabling the DSS,
8066 + * so clear it */
8067 + dispc_write_reg(DISPC_IRQSTATUS, dispc_read_reg(DISPC_IRQSTATUS));
8068 +
8069 + _omap_dispc_set_irqs();
8070 +
8071 + spin_unlock_irqrestore(&dispc.irq_lock, flags);
8072 +}
8073 +
8074 +void dispc_enable_sidle(void)
8075 +{
8076 + REG_FLD_MOD(DISPC_SYSCONFIG, 2, 4, 3); /* SIDLEMODE: smart idle */
8077 +}
8078 +
8079 +void dispc_disable_sidle(void)
8080 +{
8081 + REG_FLD_MOD(DISPC_SYSCONFIG, 1, 4, 3); /* SIDLEMODE: no idle */
8082 +}
8083 +
8084 +static void _omap_dispc_initial_config(void)
8085 +{
8086 + u32 l;
8087 +
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);
8094 +
8095 + /* FUNCGATED */
8096 + REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9);
8097 +
8098 + /* L3 firewall setting: enable access to OCM RAM */
8099 + if (cpu_is_omap24xx())
8100 + __raw_writel(0x402000b0, OMAP2_IO_ADDRESS(0x680050a0));
8101 +
8102 + _dispc_setup_color_conv_coef();
8103 +
8104 + dispc_set_loadmode(OMAP_DSS_LOAD_FRAME_ONLY);
8105 +
8106 + dispc_read_plane_fifo_sizes();
8107 +}
8108 +
8109 +int dispc_init(void)
8110 +{
8111 + u32 rev;
8112 +
8113 + spin_lock_init(&dispc.irq_lock);
8114 +
8115 + INIT_WORK(&dispc.error_work, dispc_error_worker);
8116 +
8117 + dispc.base = ioremap(DISPC_BASE, DISPC_SZ_REGS);
8118 + if (!dispc.base) {
8119 + DSSERR("can't ioremap DISPC\n");
8120 + return -ENOMEM;
8121 + }
8122 +
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");
8127 + return -ENODEV;
8128 + }
8129 + }
8130 +
8131 + enable_clocks(1);
8132 +
8133 + _omap_dispc_initial_config();
8134 +
8135 + _omap_dispc_initialize_irq();
8136 +
8137 + dispc_save_context();
8138 +
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));
8142 +
8143 + enable_clocks(0);
8144 +
8145 + return 0;
8146 +}
8147 +
8148 +void dispc_exit(void)
8149 +{
8150 + if (cpu_is_omap34xx())
8151 + clk_put(dispc.dpll4_m4_ck);
8152 + iounmap(dispc.base);
8153 +}
8154 +
8155 +int dispc_enable_plane(enum omap_plane plane, bool enable)
8156 +{
8157 + DSSDBG("dispc_enable_plane %d, %d\n", plane, enable);
8158 +
8159 + enable_clocks(1);
8160 + _dispc_enable_plane(plane, enable);
8161 + enable_clocks(0);
8162 +
8163 + return 0;
8164 +}
8165 +
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,
8172 + bool ilace,
8173 + enum omap_dss_rotation_type rotation_type,
8174 + u8 rotation, bool mirror, u8 global_alpha)
8175 +{
8176 + int r = 0;
8177 +
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,
8181 + width, height,
8182 + out_width, out_height,
8183 + ilace, color_mode,
8184 + rotation, mirror);
8185 +
8186 + enable_clocks(1);
8187 +
8188 + r = _dispc_setup_plane(plane,
8189 + paddr, screen_width,
8190 + pos_x, pos_y,
8191 + width, height,
8192 + out_width, out_height,
8193 + color_mode, ilace,
8194 + rotation_type,
8195 + rotation, mirror,
8196 + global_alpha);
8197 +
8198 + enable_clocks(0);
8199 +
8200 + return r;
8201 +}
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
8205 --- /dev/null
8206 +++ b/drivers/video/omap2/dss/display.c
8207 @@ -0,0 +1,658 @@
8208 +/*
8209 + * linux/drivers/video/omap2/dss/display.c
8210 + *
8211 + * Copyright (C) 2009 Nokia Corporation
8212 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
8213 + *
8214 + * Some code and ideas taken from drivers/video/omap/ driver
8215 + * by Imre Deak.
8216 + *
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.
8220 + *
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
8224 + * more details.
8225 + *
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/>.
8228 + */
8229 +
8230 +#define DSS_SUBSYS_NAME "DISPLAY"
8231 +
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>
8237 +
8238 +#include <mach/display.h>
8239 +#include "dss.h"
8240 +
8241 +static LIST_HEAD(display_list);
8242 +
8243 +static ssize_t display_enabled_show(struct device *dev,
8244 + struct device_attribute *attr, char *buf)
8245 +{
8246 + struct omap_dss_device *dssdev = to_dss_device(dev);
8247 + bool enabled = dssdev->state != OMAP_DSS_DISPLAY_DISABLED;
8248 +
8249 + return snprintf(buf, PAGE_SIZE, "%d\n", enabled);
8250 +}
8251 +
8252 +static ssize_t display_enabled_store(struct device *dev,
8253 + struct device_attribute *attr,
8254 + const char *buf, size_t size)
8255 +{
8256 + struct omap_dss_device *dssdev = to_dss_device(dev);
8257 + bool enabled, r;
8258 +
8259 + enabled = simple_strtoul(buf, NULL, 10);
8260 +
8261 + if (enabled != (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)) {
8262 + if (enabled) {
8263 + r = dssdev->enable(dssdev);
8264 + if (r)
8265 + return r;
8266 + } else {
8267 + dssdev->disable(dssdev);
8268 + }
8269 + }
8270 +
8271 + return size;
8272 +}
8273 +
8274 +static ssize_t display_upd_mode_show(struct device *dev,
8275 + struct device_attribute *attr, char *buf)
8276 +{
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);
8282 +}
8283 +
8284 +static ssize_t display_upd_mode_store(struct device *dev,
8285 + struct device_attribute *attr,
8286 + const char *buf, size_t size)
8287 +{
8288 + struct omap_dss_device *dssdev = to_dss_device(dev);
8289 + int val, r;
8290 + enum omap_dss_update_mode mode;
8291 +
8292 + val = simple_strtoul(buf, NULL, 10);
8293 +
8294 + switch (val) {
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;
8299 + break;
8300 + default:
8301 + return -EINVAL;
8302 + }
8303 +
8304 + r = dssdev->set_update_mode(dssdev, mode);
8305 + if (r)
8306 + return r;
8307 +
8308 + return size;
8309 +}
8310 +
8311 +static ssize_t display_tear_show(struct device *dev,
8312 + struct device_attribute *attr, char *buf)
8313 +{
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);
8317 +}
8318 +
8319 +static ssize_t display_tear_store(struct device *dev,
8320 + struct device_attribute *attr, const char *buf, size_t size)
8321 +{
8322 + struct omap_dss_device *dssdev = to_dss_device(dev);
8323 + unsigned long te;
8324 + int r;
8325 +
8326 + if (!dssdev->enable_te || !dssdev->get_te)
8327 + return -ENOENT;
8328 +
8329 + te = simple_strtoul(buf, NULL, 0);
8330 +
8331 + r = dssdev->enable_te(dssdev, te);
8332 + if (r)
8333 + return r;
8334 +
8335 + return size;
8336 +}
8337 +
8338 +static ssize_t display_timings_show(struct device *dev,
8339 + struct device_attribute *attr, char *buf)
8340 +{
8341 + struct omap_dss_device *dssdev = to_dss_device(dev);
8342 + struct omap_video_timings t;
8343 +
8344 + if (!dssdev->get_timings)
8345 + return -ENOENT;
8346 +
8347 + dssdev->get_timings(dssdev, &t);
8348 +
8349 + return snprintf(buf, PAGE_SIZE, "%u,%u/%u/%u/%u,%u/%u/%u/%u\n",
8350 + t.pixel_clock,
8351 + t.x_res, t.hfp, t.hbp, t.hsw,
8352 + t.y_res, t.vfp, t.vbp, t.vsw);
8353 +}
8354 +
8355 +static ssize_t display_timings_store(struct device *dev,
8356 + struct device_attribute *attr, const char *buf, size_t size)
8357 +{
8358 + struct omap_dss_device *dssdev = to_dss_device(dev);
8359 + struct omap_video_timings t;
8360 + int r, found;
8361 +
8362 + if (!dssdev->set_timings || !dssdev->check_timings)
8363 + return -ENOENT;
8364 +
8365 + found = 0;
8366 +#ifdef CONFIG_OMAP2_DSS_VENC
8367 + if (strncmp("pal", buf, 3) == 0) {
8368 + t = omap_dss_pal_timings;
8369 + found = 1;
8370 + } else if (strncmp("ntsc", buf, 4) == 0) {
8371 + t = omap_dss_ntsc_timings;
8372 + found = 1;
8373 + }
8374 +#endif
8375 + if (!found && sscanf(buf, "%u,%hu/%hu/%hu/%hu,%hu/%hu/%hu/%hu",
8376 + &t.pixel_clock,
8377 + &t.x_res, &t.hfp, &t.hbp, &t.hsw,
8378 + &t.y_res, &t.vfp, &t.vbp, &t.vsw) != 9)
8379 + return -EINVAL;
8380 +
8381 + r = dssdev->check_timings(dssdev, &t);
8382 + if (r)
8383 + return r;
8384 +
8385 + dssdev->set_timings(dssdev, &t);
8386 +
8387 + return size;
8388 +}
8389 +
8390 +static ssize_t display_rotate_show(struct device *dev,
8391 + struct device_attribute *attr, char *buf)
8392 +{
8393 + struct omap_dss_device *dssdev = to_dss_device(dev);
8394 + int rotate;
8395 + if (!dssdev->get_rotate)
8396 + return -ENOENT;
8397 + rotate = dssdev->get_rotate(dssdev);
8398 + return snprintf(buf, PAGE_SIZE, "%u\n", rotate);
8399 +}
8400 +
8401 +static ssize_t display_rotate_store(struct device *dev,
8402 + struct device_attribute *attr, const char *buf, size_t size)
8403 +{
8404 + struct omap_dss_device *dssdev = to_dss_device(dev);
8405 + unsigned long rot;
8406 + int r;
8407 +
8408 + if (!dssdev->set_rotate || !dssdev->get_rotate)
8409 + return -ENOENT;
8410 +
8411 + rot = simple_strtoul(buf, NULL, 0);
8412 +
8413 + r = dssdev->set_rotate(dssdev, rot);
8414 + if (r)
8415 + return r;
8416 +
8417 + return size;
8418 +}
8419 +
8420 +static ssize_t display_mirror_show(struct device *dev,
8421 + struct device_attribute *attr, char *buf)
8422 +{
8423 + struct omap_dss_device *dssdev = to_dss_device(dev);
8424 + int mirror;
8425 + if (!dssdev->get_mirror)
8426 + return -ENOENT;
8427 + mirror = dssdev->get_mirror(dssdev);
8428 + return snprintf(buf, PAGE_SIZE, "%u\n", mirror);
8429 +}
8430 +
8431 +static ssize_t display_mirror_store(struct device *dev,
8432 + struct device_attribute *attr, const char *buf, size_t size)
8433 +{
8434 + struct omap_dss_device *dssdev = to_dss_device(dev);
8435 + unsigned long mirror;
8436 + int r;
8437 +
8438 + if (!dssdev->set_mirror || !dssdev->get_mirror)
8439 + return -ENOENT;
8440 +
8441 + mirror = simple_strtoul(buf, NULL, 0);
8442 +
8443 + r = dssdev->set_mirror(dssdev, mirror);
8444 + if (r)
8445 + return r;
8446 +
8447 + return size;
8448 +}
8449 +
8450 +static ssize_t display_wss_show(struct device *dev,
8451 + struct device_attribute *attr, char *buf)
8452 +{
8453 + struct omap_dss_device *dssdev = to_dss_device(dev);
8454 + unsigned int wss;
8455 +
8456 + if (!dssdev->get_wss)
8457 + return -ENOENT;
8458 +
8459 + wss = dssdev->get_wss(dssdev);
8460 +
8461 + return snprintf(buf, PAGE_SIZE, "0x%05x\n", wss);
8462 +}
8463 +
8464 +static ssize_t display_wss_store(struct device *dev,
8465 + struct device_attribute *attr, const char *buf, size_t size)
8466 +{
8467 + struct omap_dss_device *dssdev = to_dss_device(dev);
8468 + unsigned long wss;
8469 + int r;
8470 +
8471 + if (!dssdev->get_wss || !dssdev->set_wss)
8472 + return -ENOENT;
8473 +
8474 + if (strict_strtoul(buf, 0, &wss))
8475 + return -EINVAL;
8476 +
8477 + if (wss > 0xfffff)
8478 + return -EINVAL;
8479 +
8480 + r = dssdev->set_wss(dssdev, wss);
8481 + if (r)
8482 + return r;
8483 +
8484 + return size;
8485 +}
8486 +
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);
8501 +
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,
8507 + &dev_attr_rotate,
8508 + &dev_attr_mirror,
8509 + &dev_attr_wss,
8510 + NULL
8511 +};
8512 +
8513 +static void default_get_resolution(struct omap_dss_device *dssdev,
8514 + u16 *xres, u16 *yres)
8515 +{
8516 + *xres = dssdev->panel.timings.x_res;
8517 + *yres = dssdev->panel.timings.y_res;
8518 +}
8519 +
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)
8523 +{
8524 + unsigned burst_size_bytes;
8525 +
8526 + *burst_size = OMAP_DSS_BURST_16x32;
8527 + burst_size_bytes = 16 * 32 / 8;
8528 +
8529 + *fifo_high = fifo_size - 1;
8530 + *fifo_low = fifo_size - burst_size_bytes;
8531 +}
8532 +
8533 +static int default_wait_vsync(struct omap_dss_device *dssdev)
8534 +{
8535 + unsigned long timeout = msecs_to_jiffies(500);
8536 + u32 irq;
8537 +
8538 + if (dssdev->type == OMAP_DISPLAY_TYPE_VENC)
8539 + irq = DISPC_IRQ_EVSYNC_ODD;
8540 + else
8541 + irq = DISPC_IRQ_VSYNC;
8542 +
8543 + return omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
8544 +}
8545 +
8546 +static int default_get_recommended_bpp(struct omap_dss_device *dssdev)
8547 +{
8548 + if (dssdev->panel.recommended_bpp)
8549 + return dssdev->panel.recommended_bpp;
8550 +
8551 + switch (dssdev->type) {
8552 + case OMAP_DISPLAY_TYPE_DPI:
8553 + if (dssdev->phy.dpi.data_lines == 24)
8554 + return 24;
8555 + else
8556 + return 16;
8557 +
8558 + case OMAP_DISPLAY_TYPE_DBI:
8559 + case OMAP_DISPLAY_TYPE_DSI:
8560 + if (dssdev->ctrl.pixel_size == 24)
8561 + return 24;
8562 + else
8563 + return 16;
8564 + case OMAP_DISPLAY_TYPE_VENC:
8565 + case OMAP_DISPLAY_TYPE_SDI:
8566 + return 24;
8567 + return 24;
8568 + default:
8569 + BUG();
8570 + }
8571 +}
8572 +
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)
8578 +{
8579 + int bpp;
8580 +
8581 + if (mode != OMAP_DSS_COLOR_RGB12U && mode != OMAP_DSS_COLOR_RGB16)
8582 + return false;
8583 +
8584 + if (dssdev->type == OMAP_DISPLAY_TYPE_DPI &&
8585 + (dssdev->panel.config & OMAP_DSS_LCD_TFT) == 0)
8586 + return false;
8587 +
8588 + switch (dssdev->type) {
8589 + case OMAP_DISPLAY_TYPE_DPI:
8590 + bpp = dssdev->phy.dpi.data_lines;
8591 + break;
8592 + case OMAP_DISPLAY_TYPE_VENC:
8593 + case OMAP_DISPLAY_TYPE_SDI:
8594 + bpp = 24;
8595 + break;
8596 + case OMAP_DISPLAY_TYPE_DBI:
8597 + case OMAP_DISPLAY_TYPE_DSI:
8598 + bpp = dssdev->ctrl.pixel_size;
8599 + break;
8600 + default:
8601 + BUG();
8602 + }
8603 +
8604 + return bpp > 16;
8605 +}
8606 +
8607 +void dss_init_device(struct platform_device *pdev,
8608 + struct omap_dss_device *dssdev)
8609 +{
8610 + struct device_attribute *attr;
8611 + int i;
8612 + int r;
8613 +
8614 + switch (dssdev->type) {
8615 + case OMAP_DISPLAY_TYPE_DPI:
8616 +#ifdef CONFIG_OMAP2_DSS_RFBI
8617 + case OMAP_DISPLAY_TYPE_DBI:
8618 +#endif
8619 +#ifdef CONFIG_OMAP2_DSS_SDI
8620 + case OMAP_DISPLAY_TYPE_SDI:
8621 +#endif
8622 +#ifdef CONFIG_OMAP2_DSS_DSI
8623 + case OMAP_DISPLAY_TYPE_DSI:
8624 +#endif
8625 +#ifdef CONFIG_OMAP2_DSS_VENC
8626 + case OMAP_DISPLAY_TYPE_VENC:
8627 +#endif
8628 + break;
8629 + default:
8630 + DSSERR("Support for display '%s' not compiled in.\n",
8631 + dssdev->name);
8632 + return;
8633 + }
8634 +
8635 + dssdev->get_resolution = default_get_resolution;
8636 + dssdev->get_recommended_bpp = default_get_recommended_bpp;
8637 + dssdev->wait_vsync = default_wait_vsync;
8638 +
8639 + switch (dssdev->type) {
8640 + case OMAP_DISPLAY_TYPE_DPI:
8641 + r = dpi_init_display(dssdev);
8642 + break;
8643 +#ifdef CONFIG_OMAP2_DSS_RFBI
8644 + case OMAP_DISPLAY_TYPE_DBI:
8645 + r = rfbi_init_display(dssdev);
8646 + break;
8647 +#endif
8648 +#ifdef CONFIG_OMAP2_DSS_VENC
8649 + case OMAP_DISPLAY_TYPE_VENC:
8650 + r = venc_init_display(dssdev);
8651 + break;
8652 +#endif
8653 +#ifdef CONFIG_OMAP2_DSS_SDI
8654 + case OMAP_DISPLAY_TYPE_SDI:
8655 + r = sdi_init_display(dssdev);
8656 + break;
8657 +#endif
8658 +#ifdef CONFIG_OMAP2_DSS_DSI
8659 + case OMAP_DISPLAY_TYPE_DSI:
8660 + r = dsi_init_display(dssdev);
8661 + break;
8662 +#endif
8663 + default:
8664 + BUG();
8665 + }
8666 +
8667 + if (r) {
8668 + DSSERR("failed to init display %s\n", dssdev->name);
8669 + return;
8670 + }
8671 +
8672 + /* create device sysfs files */
8673 + i = 0;
8674 + while ((attr = display_sysfs_attrs[i++]) != NULL) {
8675 + r = device_create_file(&dssdev->dev, attr);
8676 + if (r)
8677 + DSSERR("failed to create sysfs file\n");
8678 + }
8679 +
8680 + /* create display? sysfs links */
8681 + r = sysfs_create_link(&pdev->dev.kobj, &dssdev->dev.kobj,
8682 + dev_name(&dssdev->dev));
8683 + if (r)
8684 + DSSERR("failed to create sysfs display link\n");
8685 +}
8686 +
8687 +void dss_uninit_device(struct platform_device *pdev,
8688 + struct omap_dss_device *dssdev)
8689 +{
8690 + struct device_attribute *attr;
8691 + int i = 0;
8692 +
8693 + sysfs_remove_link(&pdev->dev.kobj, dev_name(&dssdev->dev));
8694 +
8695 + while ((attr = display_sysfs_attrs[i++]) != NULL)
8696 + device_remove_file(&dssdev->dev, attr);
8697 +
8698 + if (dssdev->manager)
8699 + dssdev->manager->unset_device(dssdev->manager);
8700 +}
8701 +
8702 +static int dss_suspend_device(struct device *dev, void *data)
8703 +{
8704 + int r;
8705 + struct omap_dss_device *dssdev = to_dss_device(dev);
8706 +
8707 + if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
8708 + dssdev->activate_after_resume = false;
8709 + return 0;
8710 + }
8711 +
8712 + if (!dssdev->suspend) {
8713 + DSSERR("display '%s' doesn't implement suspend\n",
8714 + dssdev->name);
8715 + return -ENOSYS;
8716 + }
8717 +
8718 + r = dssdev->suspend(dssdev);
8719 + if (r)
8720 + return r;
8721 +
8722 + dssdev->activate_after_resume = true;
8723 +
8724 + return 0;
8725 +}
8726 +
8727 +int dss_suspend_all_devices(void)
8728 +{
8729 + int r;
8730 + struct bus_type *bus = dss_get_bus();
8731 +
8732 + r = bus_for_each_dev(bus, NULL, NULL, dss_suspend_device);
8733 + if (r) {
8734 + /* resume all displays that were suspended */
8735 + dss_resume_all_devices();
8736 + return r;
8737 + }
8738 +
8739 + return 0;
8740 +}
8741 +
8742 +static int dss_resume_device(struct device *dev, void *data)
8743 +{
8744 + int r;
8745 + struct omap_dss_device *dssdev = to_dss_device(dev);
8746 +
8747 + if (dssdev->activate_after_resume && dssdev->resume) {
8748 + r = dssdev->resume(dssdev);
8749 + if (r)
8750 + return r;
8751 + }
8752 +
8753 + dssdev->activate_after_resume = false;
8754 +
8755 + return 0;
8756 +}
8757 +
8758 +int dss_resume_all_devices(void)
8759 +{
8760 + struct bus_type *bus = dss_get_bus();
8761 +
8762 + return bus_for_each_dev(bus, NULL, NULL, dss_resume_device);
8763 +}
8764 +
8765 +
8766 +void omap_dss_get_device(struct omap_dss_device *dssdev)
8767 +{
8768 + get_device(&dssdev->dev);
8769 +}
8770 +EXPORT_SYMBOL(omap_dss_get_device);
8771 +
8772 +void omap_dss_put_device(struct omap_dss_device *dssdev)
8773 +{
8774 + put_device(&dssdev->dev);
8775 +}
8776 +EXPORT_SYMBOL(omap_dss_put_device);
8777 +
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)
8781 +{
8782 + struct device *dev;
8783 + struct device *dev_start = NULL;
8784 + struct omap_dss_device *dssdev = NULL;
8785 +
8786 + int match(struct device *dev, void *data)
8787 + {
8788 + /* skip panels connected to controllers */
8789 + if (to_dss_device(dev)->panel.ctrl)
8790 + return 0;
8791 +
8792 + return 1;
8793 + }
8794 +
8795 + if (from)
8796 + dev_start = &from->dev;
8797 + dev = bus_find_device(dss_get_bus(), dev_start, NULL, match);
8798 + if (dev)
8799 + dssdev = to_dss_device(dev);
8800 + if (from)
8801 + put_device(&from->dev);
8802 +
8803 + return dssdev;
8804 +}
8805 +EXPORT_SYMBOL(omap_dss_get_next_device);
8806 +
8807 +struct omap_dss_device *omap_dss_find_device(void *data,
8808 + int (*match)(struct omap_dss_device *dssdev, void *data))
8809 +{
8810 + struct omap_dss_device *dssdev = NULL;
8811 +
8812 + while ((dssdev = omap_dss_get_next_device(dssdev)) != NULL) {
8813 + if (match(dssdev, data))
8814 + return dssdev;
8815 + }
8816 +
8817 + return NULL;
8818 +}
8819 +EXPORT_SYMBOL(omap_dss_find_device);
8820 +
8821 +int omap_dss_start_device(struct omap_dss_device *dssdev)
8822 +{
8823 + int r;
8824 +
8825 + if (!dssdev->driver) {
8826 + DSSDBG("no driver\n");
8827 + r = -ENODEV;
8828 + goto err0;
8829 + }
8830 +
8831 + if (dssdev->ctrl.panel && !dssdev->ctrl.panel->driver) {
8832 + DSSDBG("no panel driver\n");
8833 + r = -ENODEV;
8834 + goto err0;
8835 + }
8836 +
8837 + if (!try_module_get(dssdev->dev.driver->owner)) {
8838 + r = -ENODEV;
8839 + goto err0;
8840 + }
8841 +
8842 + if (dssdev->ctrl.panel) {
8843 + if (!try_module_get(dssdev->ctrl.panel->dev.driver->owner)) {
8844 + r = -ENODEV;
8845 + goto err1;
8846 + }
8847 + }
8848 +
8849 + return 0;
8850 +err1:
8851 + module_put(dssdev->dev.driver->owner);
8852 +err0:
8853 + return r;
8854 +}
8855 +EXPORT_SYMBOL(omap_dss_start_device);
8856 +
8857 +void omap_dss_stop_device(struct omap_dss_device *dssdev)
8858 +{
8859 + if (dssdev->ctrl.panel)
8860 + module_put(dssdev->ctrl.panel->dev.driver->owner);
8861 +
8862 + module_put(dssdev->dev.driver->owner);
8863 +}
8864 +EXPORT_SYMBOL(omap_dss_stop_device);
8865 +
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
8869 --- /dev/null
8870 +++ b/drivers/video/omap2/dss/dpi.c
8871 @@ -0,0 +1,388 @@
8872 +/*
8873 + * linux/drivers/video/omap2/dss/dpi.c
8874 + *
8875 + * Copyright (C) 2009 Nokia Corporation
8876 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
8877 + *
8878 + * Some code and ideas taken from drivers/video/omap/ driver
8879 + * by Imre Deak.
8880 + *
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.
8884 + *
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
8888 + * more details.
8889 + *
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/>.
8892 + */
8893 +
8894 +#define DSS_SUBSYS_NAME "DPI"
8895 +
8896 +#include <linux/kernel.h>
8897 +#include <linux/clk.h>
8898 +#include <linux/delay.h>
8899 +#include <linux/errno.h>
8900 +
8901 +#include <mach/board.h>
8902 +#include <mach/display.h>
8903 +#include <mach/cpu.h>
8904 +
8905 +#include "dss.h"
8906 +
8907 +static struct {
8908 + int update_enabled;
8909 +} dpi;
8910 +
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)
8914 +{
8915 + struct dsi_clock_info cinfo;
8916 + int r;
8917 +
8918 + r = dsi_pll_calc_pck(is_tft, pck_req, &cinfo);
8919 + if (r)
8920 + return r;
8921 +
8922 + r = dsi_pll_program(&cinfo);
8923 + if (r)
8924 + return r;
8925 +
8926 + dss_select_clk_source(0, 1);
8927 +
8928 + dispc_set_lcd_divisor(cinfo.lck_div, cinfo.pck_div);
8929 +
8930 + *fck = cinfo.dsi1_pll_fclk;
8931 + *lck_div = cinfo.lck_div;
8932 + *pck_div = cinfo.pck_div;
8933 +
8934 + return 0;
8935 +}
8936 +#else
8937 +static int dpi_set_dispc_clk(bool is_tft, unsigned long pck_req,
8938 + unsigned long *fck, int *lck_div, int *pck_div)
8939 +{
8940 + struct dispc_clock_info cinfo;
8941 + int r;
8942 +
8943 + r = dispc_calc_clock_div(is_tft, pck_req, &cinfo);
8944 + if (r)
8945 + return r;
8946 +
8947 + r = dispc_set_clock_div(&cinfo);
8948 + if (r)
8949 + return r;
8950 +
8951 + *fck = cinfo.fck;
8952 + *lck_div = cinfo.lck_div;
8953 + *pck_div = cinfo.pck_div;
8954 +
8955 + return 0;
8956 +}
8957 +#endif
8958 +
8959 +static int dpi_set_mode(struct omap_dss_device *dssdev)
8960 +{
8961 + struct omap_video_timings *t = &dssdev->panel.timings;
8962 + int lck_div, pck_div;
8963 + unsigned long fck;
8964 + unsigned long pck;
8965 + bool is_tft;
8966 + int r = 0;
8967 +
8968 + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
8969 +
8970 + dispc_set_pol_freq(dssdev->panel.config, dssdev->panel.acbi,
8971 + dssdev->panel.acb);
8972 +
8973 + is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0;
8974 +
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);
8978 +#else
8979 + r = dpi_set_dispc_clk(is_tft, t->pixel_clock * 1000,
8980 + &fck, &lck_div, &pck_div);
8981 +#endif
8982 + if (r)
8983 + goto err0;
8984 +
8985 + pck = fck / lck_div / pck_div / 1000;
8986 +
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);
8991 +
8992 + t->pixel_clock = pck;
8993 + }
8994 +
8995 + dispc_set_lcd_timings(t);
8996 +
8997 +err0:
8998 + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
8999 + return r;
9000 +}
9001 +
9002 +static int dpi_basic_init(struct omap_dss_device *dssdev)
9003 +{
9004 + bool is_tft;
9005 +
9006 + is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0;
9007 +
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);
9012 +
9013 + return 0;
9014 +}
9015 +
9016 +static int dpi_display_enable(struct omap_dss_device *dssdev)
9017 +{
9018 + int r;
9019 +
9020 + r = omap_dss_start_device(dssdev);
9021 + if (r) {
9022 + DSSERR("failed to start device\n");
9023 + goto err0;
9024 + }
9025 +
9026 + if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
9027 + DSSERR("display already enabled\n");
9028 + r = -EINVAL;
9029 + goto err1;
9030 + }
9031 +
9032 + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
9033 +
9034 + r = dpi_basic_init(dssdev);
9035 + if (r)
9036 + goto err2;
9037 +
9038 +#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
9039 + dss_clk_enable(DSS_CLK_FCK2);
9040 + r = dsi_pll_init(0, 1);
9041 + if (r)
9042 + goto err3;
9043 +#endif
9044 + r = dpi_set_mode(dssdev);
9045 + if (r)
9046 + goto err4;
9047 +
9048 + mdelay(2);
9049 +
9050 + dispc_enable_lcd_out(1);
9051 +
9052 + r = dssdev->driver->enable(dssdev);
9053 + if (r)
9054 + goto err5;
9055 +
9056 + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
9057 +
9058 + return 0;
9059 +
9060 +err5:
9061 + dispc_enable_lcd_out(0);
9062 +err4:
9063 +#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
9064 + dsi_pll_uninit();
9065 +err3:
9066 + dss_clk_disable(DSS_CLK_FCK2);
9067 +#endif
9068 +err2:
9069 + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
9070 +err1:
9071 + omap_dss_stop_device(dssdev);
9072 +err0:
9073 + return r;
9074 +}
9075 +
9076 +static int dpi_display_resume(struct omap_dss_device *dssdev);
9077 +
9078 +static void dpi_display_disable(struct omap_dss_device *dssdev)
9079 +{
9080 + if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED)
9081 + return;
9082 +
9083 + if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED)
9084 + dpi_display_resume(dssdev);
9085 +
9086 + dssdev->driver->disable(dssdev);
9087 +
9088 + dispc_enable_lcd_out(0);
9089 +
9090 +#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
9091 + dss_select_clk_source(0, 0);
9092 + dsi_pll_uninit();
9093 + dss_clk_disable(DSS_CLK_FCK2);
9094 +#endif
9095 +
9096 + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
9097 +
9098 + dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
9099 +
9100 + omap_dss_stop_device(dssdev);
9101 +}
9102 +
9103 +static int dpi_display_suspend(struct omap_dss_device *dssdev)
9104 +{
9105 + if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
9106 + return -EINVAL;
9107 +
9108 + DSSDBG("dpi_display_suspend\n");
9109 +
9110 + if (dssdev->driver->suspend)
9111 + dssdev->driver->suspend(dssdev);
9112 +
9113 + dispc_enable_lcd_out(0);
9114 +
9115 + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
9116 +
9117 + dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
9118 +
9119 + return 0;
9120 +}
9121 +
9122 +static int dpi_display_resume(struct omap_dss_device *dssdev)
9123 +{
9124 + if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED)
9125 + return -EINVAL;
9126 +
9127 + DSSDBG("dpi_display_resume\n");
9128 +
9129 + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
9130 +
9131 + dispc_enable_lcd_out(1);
9132 +
9133 + if (dssdev->driver->resume)
9134 + dssdev->driver->resume(dssdev);
9135 +
9136 + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
9137 +
9138 + return 0;
9139 +}
9140 +
9141 +static void dpi_set_timings(struct omap_dss_device *dssdev,
9142 + struct omap_video_timings *timings)
9143 +{
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);
9149 + }
9150 +}
9151 +
9152 +static int dpi_check_timings(struct omap_dss_device *dssdev,
9153 + struct omap_video_timings *timings)
9154 +{
9155 + bool is_tft;
9156 + int r;
9157 + int lck_div, pck_div;
9158 + unsigned long fck;
9159 + unsigned long pck;
9160 +
9161 + if (!dispc_lcd_timings_ok(timings))
9162 + return -EINVAL;
9163 +
9164 + if (timings->pixel_clock == 0)
9165 + return -EINVAL;
9166 +
9167 + is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0;
9168 +
9169 +#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
9170 + {
9171 + struct dsi_clock_info cinfo;
9172 + r = dsi_pll_calc_pck(is_tft, timings->pixel_clock * 1000,
9173 + &cinfo);
9174 +
9175 + if (r)
9176 + return r;
9177 +
9178 + fck = cinfo.dsi1_pll_fclk;
9179 + lck_div = cinfo.lck_div;
9180 + pck_div = cinfo.pck_div;
9181 + }
9182 +#else
9183 + {
9184 + struct dispc_clock_info cinfo;
9185 + r = dispc_calc_clock_div(is_tft, timings->pixel_clock * 1000,
9186 + &cinfo);
9187 +
9188 + if (r)
9189 + return r;
9190 +
9191 + fck = cinfo.fck;
9192 + lck_div = cinfo.lck_div;
9193 + pck_div = cinfo.pck_div;
9194 + }
9195 +#endif
9196 +
9197 + pck = fck / lck_div / pck_div / 1000;
9198 +
9199 + timings->pixel_clock = pck;
9200 +
9201 + return 0;
9202 +}
9203 +
9204 +static void dpi_get_timings(struct omap_dss_device *dssdev,
9205 + struct omap_video_timings *timings)
9206 +{
9207 + *timings = dssdev->panel.timings;
9208 +}
9209 +
9210 +static int dpi_display_set_update_mode(struct omap_dss_device *dssdev,
9211 + enum omap_dss_update_mode mode)
9212 +{
9213 + if (mode == OMAP_DSS_UPDATE_MANUAL)
9214 + return -EINVAL;
9215 +
9216 + if (mode == OMAP_DSS_UPDATE_DISABLED) {
9217 + dispc_enable_lcd_out(0);
9218 + dpi.update_enabled = 0;
9219 + } else {
9220 + dispc_enable_lcd_out(1);
9221 + dpi.update_enabled = 1;
9222 + }
9223 +
9224 + return 0;
9225 +}
9226 +
9227 +static enum omap_dss_update_mode dpi_display_get_update_mode(
9228 + struct omap_dss_device *dssdev)
9229 +{
9230 + return dpi.update_enabled ? OMAP_DSS_UPDATE_AUTO :
9231 + OMAP_DSS_UPDATE_DISABLED;
9232 +}
9233 +
9234 +int dpi_init_display(struct omap_dss_device *dssdev)
9235 +{
9236 + DSSDBG("init_display\n");
9237 +
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;
9247 +
9248 + return 0;
9249 +}
9250 +
9251 +int dpi_init(void)
9252 +{
9253 + return 0;
9254 +}
9255 +
9256 +void dpi_exit(void)
9257 +{
9258 +}
9259 +
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
9263 --- /dev/null
9264 +++ b/drivers/video/omap2/dss/dsi.c
9265 @@ -0,0 +1,3509 @@
9266 +/*
9267 + * linux/drivers/video/omap2/dss/dsi.c
9268 + *
9269 + * Copyright (C) 2009 Nokia Corporation
9270 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
9271 + *
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.
9275 + *
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
9279 + * more details.
9280 + *
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/>.
9283 + */
9284 +
9285 +#define DSS_SUBSYS_NAME "DSI"
9286 +
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>
9300 +
9301 +#include <mach/board.h>
9302 +#include <mach/display.h>
9303 +#include <mach/clock.h>
9304 +
9305 +#include "dss.h"
9306 +
9307 +/*#define VERBOSE_IRQ*/
9308 +
9309 +#define DSI_BASE 0x4804FC00
9310 +
9311 +struct dsi_reg { u16 idx; };
9312 +
9313 +#define DSI_REG(idx) ((const struct dsi_reg) { idx })
9314 +
9315 +#define DSI_SZ_REGS SZ_1K
9316 +/* DSI Protocol Engine */
9317 +
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))
9351 +
9352 +/* DSIPHY_SCP */
9353 +
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)
9358 +
9359 +/* DSI_PLL_CTRL_SCP */
9360 +
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)
9366 +
9367 +#define REG_GET(idx, start, end) \
9368 + FLD_GET(dsi_read_reg(idx), start, end)
9369 +
9370 +#define REG_FLD_MOD(idx, val, start, end) \
9371 + dsi_write_reg(idx, FLD_MOD(dsi_read_reg(idx), val, start, end))
9372 +
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
9395 +
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)
9410 +
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)
9432 +
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
9439 +
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
9444 +
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)
9451 +
9452 +enum fifo_size {
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,
9458 +};
9459 +
9460 +enum dsi_vc_mode {
9461 + DSI_VC_MODE_L4 = 0,
9462 + DSI_VC_MODE_VP,
9463 +};
9464 +
9465 +struct dsi_update_region {
9466 + bool dirty;
9467 + u16 x, y, w, h;
9468 + struct omap_dss_device *device;
9469 +};
9470 +
9471 +static struct
9472 +{
9473 + void __iomem *base;
9474 +
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 */
9479 +
9480 + struct regulator *vdds_dsi_reg;
9481 +
9482 + struct {
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 */
9487 + } vc[4];
9488 +
9489 + struct mutex lock;
9490 + struct mutex bus_lock;
9491 +
9492 + unsigned pll_locked;
9493 +
9494 + struct completion bta_completion;
9495 +
9496 + struct task_struct *thread;
9497 + wait_queue_head_t waitqueue;
9498 +
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;
9504 +
9505 + enum omap_dss_update_mode user_update_mode;
9506 + enum omap_dss_update_mode update_mode;
9507 + bool te_enabled;
9508 + bool use_ext_te;
9509 +
9510 + unsigned long cache_req_pck;
9511 + unsigned long cache_clk_freq;
9512 + struct dsi_clock_info cache_cinfo;
9513 +
9514 + u32 errors;
9515 + spinlock_t errors_lock;
9516 +#ifdef DEBUG
9517 + ktime_t perf_setup_time;
9518 + ktime_t perf_start_time;
9519 + ktime_t perf_start_time_auto;
9520 + int perf_measure_frames;
9521 +#endif
9522 + int debug_read;
9523 + int debug_write;
9524 +} dsi;
9525 +
9526 +#ifdef DEBUG
9527 +static unsigned int dsi_perf;
9528 +module_param_named(dsi_perf, dsi_perf, bool, 0644);
9529 +#endif
9530 +
9531 +static inline void dsi_write_reg(const struct dsi_reg idx, u32 val)
9532 +{
9533 + __raw_writel(val, dsi.base + idx.idx);
9534 +}
9535 +
9536 +static inline u32 dsi_read_reg(const struct dsi_reg idx)
9537 +{
9538 + return __raw_readl(dsi.base + idx.idx);
9539 +}
9540 +
9541 +
9542 +void dsi_save_context(void)
9543 +{
9544 +}
9545 +
9546 +void dsi_restore_context(void)
9547 +{
9548 +}
9549 +
9550 +void dsi_bus_lock(void)
9551 +{
9552 + mutex_lock(&dsi.bus_lock);
9553 +}
9554 +EXPORT_SYMBOL(dsi_bus_lock);
9555 +
9556 +void dsi_bus_unlock(void)
9557 +{
9558 + mutex_unlock(&dsi.bus_lock);
9559 +}
9560 +EXPORT_SYMBOL(dsi_bus_unlock);
9561 +
9562 +static inline int wait_for_bit_change(const struct dsi_reg idx, int bitnum,
9563 + int value)
9564 +{
9565 + int t = 100000;
9566 +
9567 + while (REG_GET(idx, bitnum, bitnum) != value) {
9568 + if (--t == 0)
9569 + return !value;
9570 + }
9571 +
9572 + return value;
9573 +}
9574 +
9575 +#ifdef DEBUG
9576 +static void dsi_perf_mark_setup(void)
9577 +{
9578 + dsi.perf_setup_time = ktime_get();
9579 +}
9580 +
9581 +static void dsi_perf_mark_start(void)
9582 +{
9583 + dsi.perf_start_time = ktime_get();
9584 +}
9585 +
9586 +static void dsi_perf_mark_start_auto(void)
9587 +{
9588 + dsi.perf_measure_frames = 0;
9589 + dsi.perf_start_time_auto = ktime_get();
9590 +}
9591 +
9592 +static void dsi_perf_show(const char *name)
9593 +{
9594 + ktime_t t, setup_time, trans_time;
9595 + u32 total_bytes;
9596 + u32 setup_us, trans_us, total_us;
9597 +
9598 + if (!dsi_perf)
9599 + return;
9600 +
9601 + if (dsi.update_mode == OMAP_DSS_UPDATE_DISABLED)
9602 + return;
9603 +
9604 + t = ktime_get();
9605 +
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)
9609 + setup_us = 1;
9610 +
9611 + trans_time = ktime_sub(t, dsi.perf_start_time);
9612 + trans_us = (u32)ktime_to_us(trans_time);
9613 + if (trans_us == 0)
9614 + trans_us = 1;
9615 +
9616 + total_us = setup_us + trans_us;
9617 +
9618 + total_bytes = dsi.active_update_region.w *
9619 + dsi.active_update_region.h *
9620 + dsi.active_update_region.device->ctrl.pixel_size / 8;
9621 +
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;
9629 +
9630 + dsi.perf_measure_frames++;
9631 +
9632 + if (setup_us < s_min_setup_us)
9633 + s_min_setup_us = setup_us;
9634 +
9635 + if (setup_us > s_max_setup_us)
9636 + s_max_setup_us = setup_us;
9637 +
9638 + s_total_setup_us += setup_us;
9639 +
9640 + if (trans_us < s_min_trans_us)
9641 + s_min_trans_us = trans_us;
9642 +
9643 + if (trans_us > s_max_trans_us)
9644 + s_max_trans_us = trans_us;
9645 +
9646 + s_total_trans_us += trans_us;
9647 +
9648 + if (dsi.perf_measure_frames < numframes)
9649 + return;
9650 +
9651 + total_time_auto = ktime_sub(t, dsi.perf_start_time_auto);
9652 + total_time_auto_us = (u32)ktime_to_us(total_time_auto);
9653 +
9654 + printk(KERN_INFO "DSI(%s): %u fps, setup %u/%u/%u, "
9655 + "trans %u/%u/%u\n",
9656 + name,
9657 + 1000 * 1000 * numframes / total_time_auto_us,
9658 + s_min_setup_us,
9659 + s_max_setup_us,
9660 + s_total_setup_us / numframes,
9661 + s_min_trans_us,
9662 + s_max_trans_us,
9663 + s_total_trans_us / numframes);
9664 +
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();
9672 + } else {
9673 + printk(KERN_INFO "DSI(%s): %u us + %u us = %u us (%uHz), "
9674 + "%u bytes, %u kbytes/sec\n",
9675 + name,
9676 + setup_us,
9677 + trans_us,
9678 + total_us,
9679 + 1000*1000 / total_us,
9680 + total_bytes,
9681 + total_bytes * 1000 / total_us);
9682 + }
9683 +}
9684 +#else
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)
9689 +#endif
9690 +
9691 +static void print_irq_status(u32 status)
9692 +{
9693 +#ifndef VERBOSE_IRQ
9694 + if ((status & ~DSI_IRQ_CHANNEL_MASK) == 0)
9695 + return;
9696 +#endif
9697 + printk(KERN_DEBUG "DSI IRQ: 0x%x: ", status);
9698 +
9699 +#define PIS(x) \
9700 + if (status & DSI_IRQ_##x) \
9701 + printk(#x " ");
9702 +#ifdef VERBOSE_IRQ
9703 + PIS(VC0);
9704 + PIS(VC1);
9705 + PIS(VC2);
9706 + PIS(VC3);
9707 +#endif
9708 + PIS(WAKEUP);
9709 + PIS(RESYNC);
9710 + PIS(PLL_LOCK);
9711 + PIS(PLL_UNLOCK);
9712 + PIS(PLL_RECALL);
9713 + PIS(COMPLEXIO_ERR);
9714 + PIS(HS_TX_TIMEOUT);
9715 + PIS(LP_RX_TIMEOUT);
9716 + PIS(TE_TRIGGER);
9717 + PIS(ACK_TRIGGER);
9718 + PIS(SYNC_LOST);
9719 + PIS(LDO_POWER_GOOD);
9720 + PIS(TA_TIMEOUT);
9721 +#undef PIS
9722 +
9723 + printk("\n");
9724 +}
9725 +
9726 +static void print_irq_status_vc(int channel, u32 status)
9727 +{
9728 +#ifndef VERBOSE_IRQ
9729 + if ((status & ~DSI_VC_IRQ_PACKET_SENT) == 0)
9730 + return;
9731 +#endif
9732 + printk(KERN_DEBUG "DSI VC(%d) IRQ 0x%x: ", channel, status);
9733 +
9734 +#define PIS(x) \
9735 + if (status & DSI_VC_IRQ_##x) \
9736 + printk(#x " ");
9737 + PIS(CS);
9738 + PIS(ECC_CORR);
9739 +#ifdef VERBOSE_IRQ
9740 + PIS(PACKET_SENT);
9741 +#endif
9742 + PIS(FIFO_TX_OVF);
9743 + PIS(FIFO_RX_OVF);
9744 + PIS(BTA);
9745 + PIS(ECC_NO_CORR);
9746 + PIS(FIFO_TX_UDF);
9747 + PIS(PP_BUSY_CHANGE);
9748 +#undef PIS
9749 + printk("\n");
9750 +}
9751 +
9752 +static void print_irq_status_cio(u32 status)
9753 +{
9754 + printk(KERN_DEBUG "DSI CIO IRQ 0x%x: ", status);
9755 +
9756 +#define PIS(x) \
9757 + if (status & DSI_CIO_IRQ_##x) \
9758 + printk(#x " ");
9759 + PIS(ERRSYNCESC1);
9760 + PIS(ERRSYNCESC2);
9761 + PIS(ERRSYNCESC3);
9762 + PIS(ERRESC1);
9763 + PIS(ERRESC2);
9764 + PIS(ERRESC3);
9765 + PIS(ERRCONTROL1);
9766 + PIS(ERRCONTROL2);
9767 + PIS(ERRCONTROL3);
9768 + PIS(STATEULPS1);
9769 + PIS(STATEULPS2);
9770 + PIS(STATEULPS3);
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);
9779 +#undef PIS
9780 +
9781 + printk("\n");
9782 +}
9783 +
9784 +static int debug_irq;
9785 +
9786 +/* called from dss */
9787 +void dsi_irq_handler(void)
9788 +{
9789 + u32 irqstatus, vcstatus, ciostatus;
9790 + int i;
9791 +
9792 + irqstatus = dsi_read_reg(DSI_IRQSTATUS);
9793 +
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);
9802 + }
9803 +
9804 + for (i = 0; i < 4; ++i) {
9805 + if ((irqstatus & (1<<i)) == 0)
9806 + continue;
9807 +
9808 + vcstatus = dsi_read_reg(DSI_VC_IRQSTATUS(i));
9809 +
9810 + if (vcstatus & DSI_VC_IRQ_BTA)
9811 + complete(&dsi.bta_completion);
9812 +
9813 + if (vcstatus & DSI_VC_IRQ_ERROR_MASK) {
9814 + DSSERR("DSI VC(%d) error, vc irqstatus %x\n",
9815 + i, vcstatus);
9816 + print_irq_status_vc(i, vcstatus);
9817 + } else if (debug_irq) {
9818 + print_irq_status_vc(i, vcstatus);
9819 + }
9820 +
9821 + dsi_write_reg(DSI_VC_IRQSTATUS(i), vcstatus);
9822 + }
9823 +
9824 + if (irqstatus & DSI_IRQ_COMPLEXIO_ERR) {
9825 + ciostatus = dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS);
9826 +
9827 + dsi_write_reg(DSI_COMPLEXIO_IRQ_STATUS, ciostatus);
9828 +
9829 + DSSERR("DSI CIO error, cio irqstatus %x\n", ciostatus);
9830 + print_irq_status_cio(ciostatus);
9831 + }
9832 +
9833 + dsi_write_reg(DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK);
9834 +}
9835 +
9836 +
9837 +static void _dsi_initialize_irq(void)
9838 +{
9839 + u32 l;
9840 + int i;
9841 +
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);
9847 +
9848 + /* clear interrupt status */
9849 + l = dsi_read_reg(DSI_IRQSTATUS);
9850 + dsi_write_reg(DSI_IRQSTATUS, l & ~DSI_IRQ_CHANNEL_MASK);
9851 +
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);
9855 + }
9856 +
9857 + l = dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS);
9858 + dsi_write_reg(DSI_COMPLEXIO_IRQ_STATUS, l);
9859 +
9860 + /* enable error irqs */
9861 + l = DSI_IRQ_ERROR_MASK;
9862 + dsi_write_reg(DSI_IRQENABLE, l);
9863 +
9864 + l = DSI_VC_IRQ_ERROR_MASK;
9865 + for (i = 0; i < 4; ++i)
9866 + dsi_write_reg(DSI_VC_IRQENABLE(i), l);
9867 +
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));
9873 +}
9874 +
9875 +static u32 dsi_get_errors(void)
9876 +{
9877 + unsigned long flags;
9878 + u32 e;
9879 + spin_lock_irqsave(&dsi.errors_lock, flags);
9880 + e = dsi.errors;
9881 + dsi.errors = 0;
9882 + spin_unlock_irqrestore(&dsi.errors_lock, flags);
9883 + return e;
9884 +}
9885 +
9886 +static void dsi_vc_enable_bta_irq(int channel)
9887 +{
9888 + u32 l;
9889 +
9890 + dsi_write_reg(DSI_VC_IRQSTATUS(channel), DSI_VC_IRQ_BTA);
9891 +
9892 + l = dsi_read_reg(DSI_VC_IRQENABLE(channel));
9893 + l |= DSI_VC_IRQ_BTA;
9894 + dsi_write_reg(DSI_VC_IRQENABLE(channel), l);
9895 +}
9896 +
9897 +static void dsi_vc_disable_bta_irq(int channel)
9898 +{
9899 + u32 l;
9900 +
9901 + l = dsi_read_reg(DSI_VC_IRQENABLE(channel));
9902 + l &= ~DSI_VC_IRQ_BTA;
9903 + dsi_write_reg(DSI_VC_IRQENABLE(channel), l);
9904 +}
9905 +
9906 +/* DSI func clock. this could also be DSI2_PLL_FCLK */
9907 +static inline void enable_clocks(bool enable)
9908 +{
9909 + if (enable)
9910 + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
9911 + else
9912 + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
9913 +}
9914 +
9915 +/* source clock for DSI PLL. this could also be PCLKFREE */
9916 +static inline void dsi_enable_pll_clock(bool enable)
9917 +{
9918 + if (enable)
9919 + dss_clk_enable(DSS_CLK_FCK2);
9920 + else
9921 + dss_clk_disable(DSS_CLK_FCK2);
9922 +
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");
9926 + }
9927 +}
9928 +
9929 +#ifdef DEBUG
9930 +static void _dsi_print_reset_status(void)
9931 +{
9932 + u32 l;
9933 +
9934 + if (!dss_debug)
9935 + return;
9936 +
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
9939 + * I/O. */
9940 + l = dsi_read_reg(DSI_DSIPHY_CFG5);
9941 +
9942 + printk(KERN_DEBUG "DSI resets: ");
9943 +
9944 + l = dsi_read_reg(DSI_PLL_STATUS);
9945 + printk("PLL (%d) ", FLD_GET(l, 0, 0));
9946 +
9947 + l = dsi_read_reg(DSI_COMPLEXIO_CFG1);
9948 + printk("CIO (%d) ", FLD_GET(l, 29, 29));
9949 +
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));
9956 +}
9957 +#else
9958 +#define _dsi_print_reset_status()
9959 +#endif
9960 +
9961 +static inline int dsi_if_enable(bool enable)
9962 +{
9963 + DSSDBG("dsi_if_enable(%d)\n", enable);
9964 +
9965 + enable = enable ? 1 : 0;
9966 + REG_FLD_MOD(DSI_CTRL, enable, 0, 0); /* IF_EN */
9967 +
9968 + if (wait_for_bit_change(DSI_CTRL, 0, enable) != enable) {
9969 + DSSERR("Failed to set dsi_if_enable to %d\n", enable);
9970 + return -EIO;
9971 + }
9972 +
9973 + return 0;
9974 +}
9975 +
9976 +static unsigned long dsi_fclk_rate(void)
9977 +{
9978 + unsigned long r;
9979 +
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);
9983 + } else {
9984 + /* DSI FCLK source is DSI2_PLL_FCLK */
9985 + r = dsi.dsi2_pll_fclk;
9986 + }
9987 +
9988 + return r;
9989 +}
9990 +
9991 +static int dsi_set_lp_clk_divisor(struct omap_dss_device *dssdev)
9992 +{
9993 + unsigned n;
9994 + unsigned long dsi_fclk;
9995 + unsigned long lp_clk, lp_clk_req;
9996 +
9997 + dsi_fclk = dsi_fclk_rate();
9998 +
9999 + lp_clk_req = dssdev->phy.dsi.lp_clk_hz;
10000 +
10001 + for (n = 1; n < (1 << 13) - 1; ++n) {
10002 + lp_clk = dsi_fclk / 2 / n;
10003 + if (lp_clk <= lp_clk_req)
10004 + break;
10005 + }
10006 +
10007 + if (n == (1 << 13) - 1) {
10008 + DSSERR("Failed to find LP_CLK_DIVISOR\n");
10009 + return -EINVAL;
10010 + }
10011 +
10012 + DSSDBG("LP_CLK_DIV %u, LP_CLK %lu (req %lu)\n", n, lp_clk, lp_clk_req);
10013 +
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 */
10017 +
10018 + return 0;
10019 +}
10020 +
10021 +
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,
10027 +};
10028 +
10029 +static int dsi_pll_power(enum dsi_pll_power_state state)
10030 +{
10031 + int t = 0;
10032 +
10033 + REG_FLD_MOD(DSI_CLK_CTRL, state, 31, 30); /* PLL_PWR_CMD */
10034 +
10035 + /* PLL_PWR_STATUS */
10036 + while (FLD_GET(dsi_read_reg(DSI_CLK_CTRL), 29, 28) != state) {
10037 + udelay(1);
10038 + if (t++ > 1000) {
10039 + DSSERR("Failed to set DSI PLL power mode to %d\n",
10040 + state);
10041 + return -ENODEV;
10042 + }
10043 + }
10044 +
10045 + return 0;
10046 +}
10047 +
10048 +int dsi_pll_calc_pck(bool is_tft, unsigned long req_pck,
10049 + struct dsi_clock_info *cinfo)
10050 +{
10051 + struct dsi_clock_info cur, best;
10052 + int min_fck_per_pck;
10053 + int match = 0;
10054 + unsigned long dss_clk_fck2;
10055 +
10056 + dss_clk_fck2 = dss_clk_get_rate(DSS_CLK_FCK2);
10057 +
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;
10062 + return 0;
10063 + }
10064 +
10065 + min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
10066 +
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;
10073 + }
10074 +
10075 + DSSDBG("dsi_pll_calc\n");
10076 +
10077 +retry:
10078 + memset(&best, 0, sizeof(best));
10079 +
10080 + memset(&cur, 0, sizeof(cur));
10081 + cur.clkin = dss_clk_fck2;
10082 + cur.use_dss2_fck = 1;
10083 + cur.highfreq = 0;
10084 +
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;
10091 + else
10092 + cur.fint = cur.clkin / (2 * cur.regn);
10093 +
10094 + if (cur.fint > FINT_MAX || cur.fint < FINT_MIN)
10095 + continue;
10096 +
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;
10100 +
10101 + a = 2 * cur.regm * (cur.clkin/1000);
10102 + b = cur.regn * (cur.highfreq + 1);
10103 + cur.dsiphy = a / b * 1000;
10104 +
10105 + if (cur.dsiphy > 1800 * 1000 * 1000)
10106 + break;
10107 +
10108 + /* DSI1_PLL_FCLK(MHz) = DSIPHY(MHz) / regm3 < 173MHz */
10109 + for (cur.regm3 = 1; cur.regm3 < REGM3_MAX;
10110 + ++cur.regm3) {
10111 + cur.dsi1_pll_fclk = cur.dsiphy / cur.regm3;
10112 +
10113 + /* this will narrow down the search a bit,
10114 + * but still give pixclocks below what was
10115 + * requested */
10116 + if (cur.dsi1_pll_fclk < req_pck)
10117 + break;
10118 +
10119 + if (cur.dsi1_pll_fclk > DISPC_MAX_FCK)
10120 + continue;
10121 +
10122 + if (min_fck_per_pck &&
10123 + cur.dsi1_pll_fclk <
10124 + req_pck * min_fck_per_pck)
10125 + continue;
10126 +
10127 + match = 1;
10128 +
10129 + find_lck_pck_divs(is_tft, req_pck,
10130 + cur.dsi1_pll_fclk,
10131 + &cur.lck_div,
10132 + &cur.pck_div);
10133 +
10134 + cur.lck = cur.dsi1_pll_fclk / cur.lck_div;
10135 + cur.pck = cur.lck / cur.pck_div;
10136 +
10137 + if (abs(cur.pck - req_pck) <
10138 + abs(best.pck - req_pck)) {
10139 + best = cur;
10140 +
10141 + if (cur.pck == req_pck)
10142 + goto found;
10143 + }
10144 + }
10145 + }
10146 + }
10147 +found:
10148 + if (!match) {
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;
10154 + goto retry;
10155 + }
10156 +
10157 + DSSERR("Could not find suitable clock settings.\n");
10158 +
10159 + return -EINVAL;
10160 + }
10161 +
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)
10167 + best.regm4 = 1;
10168 + best.dsi2_pll_fclk = best.dsiphy / best.regm4;
10169 +
10170 + if (cinfo)
10171 + *cinfo = best;
10172 +
10173 + dsi.cache_req_pck = req_pck;
10174 + dsi.cache_clk_freq = 0;
10175 + dsi.cache_cinfo = best;
10176 +
10177 + return 0;
10178 +}
10179 +
10180 +static int dsi_pll_calc_ddrfreq(unsigned long clk_freq,
10181 + struct dsi_clock_info *cinfo)
10182 +{
10183 + struct dsi_clock_info cur, best;
10184 + const bool use_dss2_fck = 1;
10185 + unsigned long datafreq;
10186 + unsigned long dss_clk_fck2;
10187 +
10188 + DSSDBG("dsi_pll_calc_ddrfreq\n");
10189 +
10190 + dss_clk_fck2 = dss_clk_get_rate(DSS_CLK_FCK2);
10191 +
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;
10196 + return 0;
10197 + }
10198 +
10199 + datafreq = clk_freq * 4;
10200 +
10201 + memset(&best, 0, sizeof(best));
10202 +
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;
10208 + } else {
10209 + cur.clkin = dispc_pclk_rate();
10210 + if (cur.clkin < 32000000)
10211 + cur.highfreq = 0;
10212 + else
10213 + cur.highfreq = 1;
10214 + }
10215 +
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;
10222 + else
10223 + cur.fint = cur.clkin / (2 * cur.regn);
10224 +
10225 + if (cur.fint > FINT_MAX || cur.fint < FINT_MIN)
10226 + continue;
10227 +
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;
10231 +
10232 + a = 2 * cur.regm * (cur.clkin/1000);
10233 + b = cur.regn * (cur.highfreq + 1);
10234 + cur.dsiphy = a / b * 1000;
10235 +
10236 + if (cur.dsiphy > 1800 * 1000 * 1000)
10237 + break;
10238 +
10239 + if (abs(cur.dsiphy - datafreq) <
10240 + abs(best.dsiphy - datafreq)) {
10241 + best = cur;
10242 + /* DSSDBG("best %ld\n", best.dsiphy); */
10243 + }
10244 +
10245 + if (cur.dsiphy == datafreq)
10246 + goto found;
10247 + }
10248 + }
10249 +found:
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)
10255 + best.regm3 = 1;
10256 + best.dsi1_pll_fclk = best.dsiphy / best.regm3;
10257 +
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)
10263 + best.regm4 = 1;
10264 + best.dsi2_pll_fclk = best.dsiphy / best.regm4;
10265 +
10266 + if (cinfo)
10267 + *cinfo = best;
10268 +
10269 + dsi.cache_clk_freq = clk_freq;
10270 + dsi.cache_req_pck = 0;
10271 + dsi.cache_cinfo = best;
10272 +
10273 + return 0;
10274 +}
10275 +
10276 +int dsi_pll_program(struct dsi_clock_info *cinfo)
10277 +{
10278 + int r = 0;
10279 + u32 l;
10280 +
10281 + DSSDBG("dsi_pll_program\n");
10282 +
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;
10287 +
10288 + DSSDBG("DSI Fint %ld\n", cinfo->fint);
10289 +
10290 + DSSDBG("clkin (%s) rate %ld, highfreq %d\n",
10291 + cinfo->use_dss2_fck ? "dss2_fck" : "pclkfree",
10292 + cinfo->clkin,
10293 + cinfo->highfreq);
10294 +
10295 + /* DSIPHY == CLKIN4DDR */
10296 + DSSDBG("DSIPHY = 2 * %d / %d * %lu / %d = %lu\n",
10297 + cinfo->regm,
10298 + cinfo->regn,
10299 + cinfo->clkin,
10300 + cinfo->highfreq + 1,
10301 + cinfo->dsiphy);
10302 +
10303 + DSSDBG("Data rate on 1 DSI lane %ld Mbps\n",
10304 + dsi.dsiphy / 1000 / 1000 / 2);
10305 +
10306 + DSSDBG("Clock lane freq %ld Hz\n", dsi.ddr_clk);
10307 +
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);
10312 +
10313 + REG_FLD_MOD(DSI_PLL_CONTROL, 0, 0, 0); /* DSI_PLL_AUTOMODE = manual */
10314 +
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);
10322 +
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);
10332 +
10333 + REG_FLD_MOD(DSI_PLL_GO, 1, 0, 0); /* DSI_PLL_GO */
10334 +
10335 + if (wait_for_bit_change(DSI_PLL_GO, 0, 0) != 0) {
10336 + DSSERR("dsi pll go bit not going down.\n");
10337 + r = -EIO;
10338 + goto err;
10339 + }
10340 +
10341 + if (wait_for_bit_change(DSI_PLL_STATUS, 1, 1) != 1) {
10342 + DSSERR("cannot lock PLL\n");
10343 + r = -EIO;
10344 + goto err;
10345 + }
10346 +
10347 + dsi.pll_locked = 1;
10348 +
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);
10365 +
10366 + DSSDBG("PLL config done\n");
10367 +err:
10368 + return r;
10369 +}
10370 +
10371 +int dsi_pll_init(bool enable_hsclk, bool enable_hsdiv)
10372 +{
10373 + int r = 0;
10374 + enum dsi_pll_power_state pwstate;
10375 + struct dispc_clock_info cinfo;
10376 +
10377 + DSSDBG("PLL init\n");
10378 +
10379 + enable_clocks(1);
10380 + dsi_enable_pll_clock(1);
10381 +
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);
10387 + if (r)
10388 + goto err0;
10389 +
10390 + r = dispc_set_clock_div(&cinfo);
10391 + if (r) {
10392 + DSSERR("Failed to set basic clocks\n");
10393 + goto err0;
10394 + }
10395 +
10396 + r = regulator_enable(dsi.vdds_dsi_reg);
10397 + if (r)
10398 + goto err0;
10399 +
10400 + /* XXX PLL does not come out of reset without this... */
10401 + dispc_pck_free_enable(1);
10402 +
10403 + if (wait_for_bit_change(DSI_PLL_STATUS, 0, 1) != 1) {
10404 + DSSERR("PLL not coming out of reset.\n");
10405 + r = -ENODEV;
10406 + goto err1;
10407 + }
10408 +
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);
10412 +
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;
10419 + else
10420 + pwstate = DSI_PLL_POWER_OFF;
10421 +
10422 + r = dsi_pll_power(pwstate);
10423 +
10424 + if (r)
10425 + goto err1;
10426 +
10427 + DSSDBG("PLL init done\n");
10428 +
10429 + return 0;
10430 +err1:
10431 + regulator_disable(dsi.vdds_dsi_reg);
10432 +err0:
10433 + enable_clocks(0);
10434 + dsi_enable_pll_clock(0);
10435 + return r;
10436 +}
10437 +
10438 +void dsi_pll_uninit(void)
10439 +{
10440 + enable_clocks(0);
10441 + dsi_enable_pll_clock(0);
10442 +
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");
10447 +}
10448 +
10449 +unsigned long dsi_get_dsi1_pll_rate(void)
10450 +{
10451 + return dsi.dsi1_pll_fclk;
10452 +}
10453 +
10454 +unsigned long dsi_get_dsi2_pll_rate(void)
10455 +{
10456 + return dsi.dsi2_pll_fclk;
10457 +}
10458 +
10459 +void dsi_dump_clocks(struct seq_file *s)
10460 +{
10461 + int clksel;
10462 +
10463 + enable_clocks(1);
10464 +
10465 + clksel = REG_GET(DSI_PLL_CONFIGURATION2, 11, 11);
10466 +
10467 + seq_printf(s, "- dsi -\n");
10468 +
10469 + seq_printf(s, "dsi fclk source = %s\n",
10470 + dss_get_dsi_clk_source() == 0 ?
10471 + "dss1_alwon_fclk" : "dsi2_pll_fclk");
10472 +
10473 + seq_printf(s, "dsi pll source = %s\n",
10474 + clksel == 0 ?
10475 + "dss2_alwon_fclk" : "pclkfree");
10476 +
10477 + seq_printf(s, "DSIPHY\t\t%lu\nDDR_CLK\t\t%lu\n",
10478 + dsi.dsiphy, dsi.ddr_clk);
10479 +
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");
10486 +
10487 + enable_clocks(0);
10488 +}
10489 +
10490 +void dsi_dump_regs(struct seq_file *s)
10491 +{
10492 +#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dsi_read_reg(r))
10493 +
10494 + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
10495 +
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);
10522 +
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));
10530 +
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));
10538 +
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));
10546 +
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));
10554 +
10555 + DUMPREG(DSI_DSIPHY_CFG0);
10556 + DUMPREG(DSI_DSIPHY_CFG1);
10557 + DUMPREG(DSI_DSIPHY_CFG2);
10558 + DUMPREG(DSI_DSIPHY_CFG5);
10559 +
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);
10565 +
10566 + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
10567 +#undef DUMPREG
10568 +}
10569 +
10570 +enum dsi_complexio_power_state {
10571 + DSI_COMPLEXIO_POWER_OFF = 0x0,
10572 + DSI_COMPLEXIO_POWER_ON = 0x1,
10573 + DSI_COMPLEXIO_POWER_ULPS = 0x2,
10574 +};
10575 +
10576 +static int dsi_complexio_power(enum dsi_complexio_power_state state)
10577 +{
10578 + int t = 0;
10579 +
10580 + /* PWR_CMD */
10581 + REG_FLD_MOD(DSI_COMPLEXIO_CFG1, state, 28, 27);
10582 +
10583 + /* PWR_STATUS */
10584 + while (FLD_GET(dsi_read_reg(DSI_COMPLEXIO_CFG1), 26, 25) != state) {
10585 + udelay(1);
10586 + if (t++ > 1000) {
10587 + DSSERR("failed to set complexio power state to "
10588 + "%d\n", state);
10589 + return -ENODEV;
10590 + }
10591 + }
10592 +
10593 + return 0;
10594 +}
10595 +
10596 +static void dsi_complexio_config(struct omap_dss_device *dssdev)
10597 +{
10598 + u32 r;
10599 +
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;
10606 +
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);
10615 +
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. */
10626 +
10627 + /*
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);
10632 + */
10633 +}
10634 +
10635 +static inline unsigned ns2ddr(unsigned ns)
10636 +{
10637 + /* convert time in ns to ddr ticks, rounding up */
10638 + return (ns * (dsi.ddr_clk/1000/1000) + 999) / 1000;
10639 +}
10640 +
10641 +static inline unsigned ddr2ns(unsigned ddr)
10642 +{
10643 + return ddr * 1000 * 1000 / (dsi.ddr_clk / 1000);
10644 +}
10645 +
10646 +static void dsi_complexio_timings(void)
10647 +{
10648 + u32 r;
10649 + u32 ths_prepare, ths_prepare_ths_zero, ths_trail, ths_exit;
10650 + u32 tlpx_half, tclk_trail, tclk_zero;
10651 + u32 tclk_prepare;
10652 +
10653 + /* calculate timings */
10654 +
10655 + /* 1 * DDR_CLK = 2 * UI */
10656 +
10657 + /* min 40ns + 4*UI max 85ns + 6*UI */
10658 + ths_prepare = ns2ddr(70) + 2;
10659 +
10660 + /* min 145ns + 10*UI */
10661 + ths_prepare_ths_zero = ns2ddr(175) + 2;
10662 +
10663 + /* min max(8*UI, 60ns+4*UI) */
10664 + ths_trail = ns2ddr(60) + 5;
10665 +
10666 + /* min 100ns */
10667 + ths_exit = ns2ddr(145);
10668 +
10669 + /* tlpx min 50n */
10670 + tlpx_half = ns2ddr(25);
10671 +
10672 + /* min 60ns */
10673 + tclk_trail = ns2ddr(60) + 2;
10674 +
10675 + /* min 38ns, max 95ns */
10676 + tclk_prepare = ns2ddr(65);
10677 +
10678 + /* min tclk-prepare + tclk-zero = 300ns */
10679 + tclk_zero = ns2ddr(260);
10680 +
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));
10687 +
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));
10695 +
10696 + /* program timings */
10697 +
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);
10704 +
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);
10710 +
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);
10714 +}
10715 +
10716 +
10717 +static int dsi_complexio_init(struct omap_dss_device *dssdev)
10718 +{
10719 + int r = 0;
10720 +
10721 + DSSDBG("dsi_complexio_init\n");
10722 +
10723 + /* CIO_CLK_ICG, enable L3 clk to CIO */
10724 + REG_FLD_MOD(DSI_CLK_CTRL, 1, 14, 14);
10725 +
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
10728 + * I/O. */
10729 + dsi_read_reg(DSI_DSIPHY_CFG5);
10730 +
10731 + if (wait_for_bit_change(DSI_DSIPHY_CFG5, 30, 1) != 1) {
10732 + DSSERR("ComplexIO PHY not coming out of reset.\n");
10733 + r = -ENODEV;
10734 + goto err;
10735 + }
10736 +
10737 + dsi_complexio_config(dssdev);
10738 +
10739 + r = dsi_complexio_power(DSI_COMPLEXIO_POWER_ON);
10740 +
10741 + if (r)
10742 + goto err;
10743 +
10744 + if (wait_for_bit_change(DSI_COMPLEXIO_CFG1, 29, 1) != 1) {
10745 + DSSERR("ComplexIO not coming out of reset.\n");
10746 + r = -ENODEV;
10747 + goto err;
10748 + }
10749 +
10750 + if (wait_for_bit_change(DSI_COMPLEXIO_CFG1, 21, 1) != 1) {
10751 + DSSERR("ComplexIO LDO power down.\n");
10752 + r = -ENODEV;
10753 + goto err;
10754 + }
10755 +
10756 + dsi_complexio_timings();
10757 +
10758 + /*
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.
10769 + */
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);
10775 +
10776 + DSSDBG("CIO init done\n");
10777 +err:
10778 + return r;
10779 +}
10780 +
10781 +static void dsi_complexio_uninit(void)
10782 +{
10783 + dsi_complexio_power(DSI_COMPLEXIO_POWER_OFF);
10784 +}
10785 +
10786 +static int _dsi_wait_reset(void)
10787 +{
10788 + int i = 0;
10789 +
10790 + while (REG_GET(DSI_SYSSTATUS, 0, 0) == 0) {
10791 + if (i++ > 5) {
10792 + DSSERR("soft reset failed\n");
10793 + return -ENODEV;
10794 + }
10795 + udelay(1);
10796 + }
10797 +
10798 + return 0;
10799 +}
10800 +
10801 +static int _dsi_reset(void)
10802 +{
10803 + /* Soft reset */
10804 + REG_FLD_MOD(DSI_SYSCONFIG, 1, 1, 1);
10805 + return _dsi_wait_reset();
10806 +}
10807 +
10808 +
10809 +static void dsi_config_tx_fifo(enum fifo_size size1, enum fifo_size size2,
10810 + enum fifo_size size3, enum fifo_size size4)
10811 +{
10812 + u32 r = 0;
10813 + int add = 0;
10814 + int i;
10815 +
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;
10820 +
10821 + for (i = 0; i < 4; i++) {
10822 + u8 v;
10823 + int size = dsi.vc[i].fifo_size;
10824 +
10825 + if (add + size > 4) {
10826 + DSSERR("Illegal FIFO configuration\n");
10827 + BUG();
10828 + }
10829 +
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); */
10833 + add += size;
10834 + }
10835 +
10836 + dsi_write_reg(DSI_TX_FIFO_VC_SIZE, r);
10837 +}
10838 +
10839 +static void dsi_config_rx_fifo(enum fifo_size size1, enum fifo_size size2,
10840 + enum fifo_size size3, enum fifo_size size4)
10841 +{
10842 + u32 r = 0;
10843 + int add = 0;
10844 + int i;
10845 +
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;
10850 +
10851 + for (i = 0; i < 4; i++) {
10852 + u8 v;
10853 + int size = dsi.vc[i].fifo_size;
10854 +
10855 + if (add + size > 4) {
10856 + DSSERR("Illegal FIFO configuration\n");
10857 + BUG();
10858 + }
10859 +
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); */
10863 + add += size;
10864 + }
10865 +
10866 + dsi_write_reg(DSI_RX_FIFO_VC_SIZE, r);
10867 +}
10868 +
10869 +static int dsi_force_tx_stop_mode_io(void)
10870 +{
10871 + u32 r;
10872 +
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);
10876 +
10877 + if (wait_for_bit_change(DSI_TIMING1, 15, 0) != 0) {
10878 + DSSERR("TX_STOP bit not going down\n");
10879 + return -EIO;
10880 + }
10881 +
10882 + return 0;
10883 +}
10884 +
10885 +static void dsi_vc_print_status(int channel)
10886 +{
10887 + u32 r;
10888 +
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, ",
10892 + channel,
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));
10898 +
10899 + r = dsi_read_reg(DSI_TX_FIFO_VC_EMPTINESS);
10900 + DSSDBG("EMPTINESS %d\n", (r >> (8 * channel)) & 0xff);
10901 +}
10902 +
10903 +static int dsi_vc_enable(int channel, bool enable)
10904 +{
10905 + if (dsi.update_mode != OMAP_DSS_UPDATE_AUTO)
10906 + DSSDBG("dsi_vc_enable channel %d, enable %d\n",
10907 + channel, enable);
10908 +
10909 + enable = enable ? 1 : 0;
10910 +
10911 + REG_FLD_MOD(DSI_VC_CTRL(channel), enable, 0, 0);
10912 +
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);
10915 + return -EIO;
10916 + }
10917 +
10918 + return 0;
10919 +}
10920 +
10921 +static void dsi_vc_initial_config(int channel)
10922 +{
10923 + u32 r;
10924 +
10925 + DSSDBGF("%d", channel);
10926 +
10927 + r = dsi_read_reg(DSI_VC_CTRL(channel));
10928 +
10929 + if (FLD_GET(r, 15, 15)) /* VC_BUSY */
10930 + DSSERR("VC(%d) busy when trying to configure it!\n",
10931 + channel);
10932 +
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 */
10940 +
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 */
10943 +
10944 + dsi_write_reg(DSI_VC_CTRL(channel), r);
10945 +
10946 + dsi.vc[channel].mode = DSI_VC_MODE_L4;
10947 +}
10948 +
10949 +static void dsi_vc_config_l4(int channel)
10950 +{
10951 + if (dsi.vc[channel].mode == DSI_VC_MODE_L4)
10952 + return;
10953 +
10954 + DSSDBGF("%d", channel);
10955 +
10956 + dsi_vc_enable(channel, 0);
10957 +
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);
10960 +
10961 + REG_FLD_MOD(DSI_VC_CTRL(channel), 0, 1, 1); /* SOURCE, 0 = L4 */
10962 +
10963 + dsi_vc_enable(channel, 1);
10964 +
10965 + dsi.vc[channel].mode = DSI_VC_MODE_L4;
10966 +}
10967 +
10968 +static void dsi_vc_config_vp(int channel)
10969 +{
10970 + if (dsi.vc[channel].mode == DSI_VC_MODE_VP)
10971 + return;
10972 +
10973 + DSSDBGF("%d", channel);
10974 +
10975 + dsi_vc_enable(channel, 0);
10976 +
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);
10979 +
10980 + REG_FLD_MOD(DSI_VC_CTRL(channel), 1, 1, 1); /* SOURCE, 1 = video port */
10981 +
10982 + dsi_vc_enable(channel, 1);
10983 +
10984 + dsi.vc[channel].mode = DSI_VC_MODE_VP;
10985 +}
10986 +
10987 +
10988 +static void dsi_vc_enable_hs(int channel, bool enable)
10989 +{
10990 + DSSDBG("dsi_vc_enable_hs(%d, %d)\n", channel, enable);
10991 +
10992 + dsi_vc_enable(channel, 0);
10993 + dsi_if_enable(0);
10994 +
10995 + REG_FLD_MOD(DSI_VC_CTRL(channel), enable, 9, 9);
10996 +
10997 + dsi_vc_enable(channel, 1);
10998 + dsi_if_enable(1);
10999 +
11000 + dsi_force_tx_stop_mode_io();
11001 +}
11002 +
11003 +static void dsi_vc_flush_long_data(int channel)
11004 +{
11005 + while (REG_GET(DSI_VC_CTRL(channel), 20, 20)) {
11006 + u32 val;
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);
11013 + }
11014 +}
11015 +
11016 +static void dsi_show_rx_ack_with_err(u16 err)
11017 +{
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");
11051 +}
11052 +
11053 +static u16 dsi_vc_flush_receive_data(int channel)
11054 +{
11055 + /* RX_FIFO_NOT_EMPTY */
11056 + while (REG_GET(DSI_VC_CTRL(channel), 20, 20)) {
11057 + u32 val;
11058 + u8 dt;
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);
11075 + } else {
11076 + DSSERR("\tunknown datatype 0x%02x\n", dt);
11077 + }
11078 + }
11079 + return 0;
11080 +}
11081 +
11082 +static int dsi_vc_send_bta(int channel)
11083 +{
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);
11087 +
11088 + WARN_ON(!mutex_is_locked(&dsi.bus_lock));
11089 +
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);
11093 + }
11094 +
11095 + REG_FLD_MOD(DSI_VC_CTRL(channel), 1, 6, 6); /* BTA_EN */
11096 +
11097 + return 0;
11098 +}
11099 +
11100 +int dsi_vc_send_bta_sync(int channel)
11101 +{
11102 + int r = 0;
11103 + u32 err;
11104 +
11105 + INIT_COMPLETION(dsi.bta_completion);
11106 +
11107 + dsi_vc_enable_bta_irq(channel);
11108 +
11109 + r = dsi_vc_send_bta(channel);
11110 + if (r)
11111 + goto err;
11112 +
11113 + if (wait_for_completion_timeout(&dsi.bta_completion,
11114 + msecs_to_jiffies(500)) == 0) {
11115 + DSSERR("Failed to receive BTA\n");
11116 + r = -EIO;
11117 + goto err;
11118 + }
11119 +
11120 + err = dsi_get_errors();
11121 + if (err) {
11122 + DSSERR("Error while sending BTA: %x\n", err);
11123 + r = -EIO;
11124 + goto err;
11125 + }
11126 +err:
11127 + dsi_vc_disable_bta_irq(channel);
11128 +
11129 + return r;
11130 +}
11131 +EXPORT_SYMBOL(dsi_vc_send_bta_sync);
11132 +
11133 +static inline void dsi_vc_write_long_header(int channel, u8 data_type,
11134 + u16 len, u8 ecc)
11135 +{
11136 + u32 val;
11137 + u8 data_id;
11138 +
11139 + WARN_ON(!mutex_is_locked(&dsi.bus_lock));
11140 +
11141 + /*data_id = data_type | channel << 6; */
11142 + data_id = data_type | dsi.vc[channel].dest_per << 6;
11143 +
11144 + val = FLD_VAL(data_id, 7, 0) | FLD_VAL(len, 23, 8) |
11145 + FLD_VAL(ecc, 31, 24);
11146 +
11147 + dsi_write_reg(DSI_VC_LONG_PACKET_HEADER(channel), val);
11148 +}
11149 +
11150 +static inline void dsi_vc_write_long_payload(int channel,
11151 + u8 b1, u8 b2, u8 b3, u8 b4)
11152 +{
11153 + u32 val;
11154 +
11155 + val = b4 << 24 | b3 << 16 | b2 << 8 | b1 << 0;
11156 +
11157 +/* DSSDBG("\twriting %02x, %02x, %02x, %02x (%#010x)\n",
11158 + b1, b2, b3, b4, val); */
11159 +
11160 + dsi_write_reg(DSI_VC_LONG_PACKET_PAYLOAD(channel), val);
11161 +}
11162 +
11163 +static int dsi_vc_send_long(int channel, u8 data_type, u8 *data, u16 len,
11164 + u8 ecc)
11165 +{
11166 + /*u32 val; */
11167 + int i;
11168 + u8 *p;
11169 + int r = 0;
11170 + u8 b1, b2, b3, b4;
11171 +
11172 + if (dsi.debug_write)
11173 + DSSDBG("dsi_vc_send_long, %d bytes\n", len);
11174 +
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");
11178 + return -EINVAL;
11179 + }
11180 +
11181 + dsi_vc_config_l4(channel);
11182 +
11183 + dsi_vc_write_long_header(channel, data_type, len, ecc);
11184 +
11185 + /*dsi_vc_print_status(0); */
11186 +
11187 + p = data;
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); */
11192 +
11193 + b1 = *p++;
11194 + b2 = *p++;
11195 + b3 = *p++;
11196 + b4 = *p++;
11197 +
11198 + dsi_vc_write_long_payload(channel, b1, b2, b3, b4);
11199 + }
11200 +
11201 + i = len % 4;
11202 + if (i) {
11203 + b1 = 0; b2 = 0; b3 = 0;
11204 +
11205 + if (dsi.debug_write)
11206 + DSSDBG("\tsending remainder bytes %d\n", i);
11207 +
11208 + switch (i) {
11209 + case 3:
11210 + b1 = *p++;
11211 + b2 = *p++;
11212 + b3 = *p++;
11213 + break;
11214 + case 2:
11215 + b1 = *p++;
11216 + b2 = *p++;
11217 + break;
11218 + case 1:
11219 + b1 = *p++;
11220 + break;
11221 + }
11222 +
11223 + dsi_vc_write_long_payload(channel, b1, b2, b3, 0);
11224 + }
11225 +
11226 + return r;
11227 +}
11228 +
11229 +static int dsi_vc_send_short(int channel, u8 data_type, u16 data, u8 ecc)
11230 +{
11231 + u32 r;
11232 + u8 data_id;
11233 +
11234 + WARN_ON(!mutex_is_locked(&dsi.bus_lock));
11235 +
11236 + if (dsi.debug_write)
11237 + DSSDBG("dsi_vc_send_short(ch%d, dt %#x, b1 %#x, b2 %#x)\n",
11238 + channel,
11239 + data_type, data & 0xff, (data >> 8) & 0xff);
11240 +
11241 + dsi_vc_config_l4(channel);
11242 +
11243 + if (FLD_GET(dsi_read_reg(DSI_VC_CTRL(channel)), 16, 16)) {
11244 + DSSERR("ERROR FIFO FULL, aborting transfer\n");
11245 + return -EINVAL;
11246 + }
11247 +
11248 + data_id = data_type | channel << 6;
11249 +
11250 + r = (data_id << 0) | (data << 8) | (ecc << 24);
11251 +
11252 + dsi_write_reg(DSI_VC_SHORT_PACKET_HEADER(channel), r);
11253 +
11254 + return 0;
11255 +}
11256 +
11257 +int dsi_vc_send_null(int channel)
11258 +{
11259 + u8 nullpkg[] = {0, 0, 0, 0};
11260 + return dsi_vc_send_long(0, DSI_DT_NULL_PACKET, nullpkg, 4, 0);
11261 +}
11262 +EXPORT_SYMBOL(dsi_vc_send_null);
11263 +
11264 +int dsi_vc_dcs_write_nosync(int channel, u8 *data, int len)
11265 +{
11266 + int r;
11267 +
11268 + BUG_ON(len == 0);
11269 +
11270 + if (len == 1) {
11271 + r = dsi_vc_send_short(channel, DSI_DT_DCS_SHORT_WRITE_0,
11272 + data[0], 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);
11276 + } else {
11277 + /* 0x39 = DCS Long Write */
11278 + r = dsi_vc_send_long(channel, DSI_DT_DCS_LONG_WRITE,
11279 + data, len, 0);
11280 + }
11281 +
11282 + return r;
11283 +}
11284 +EXPORT_SYMBOL(dsi_vc_dcs_write_nosync);
11285 +
11286 +int dsi_vc_dcs_write(int channel, u8 *data, int len)
11287 +{
11288 + int r;
11289 +
11290 + r = dsi_vc_dcs_write_nosync(channel, data, len);
11291 + if (r)
11292 + return r;
11293 +
11294 + r = dsi_vc_send_bta_sync(channel);
11295 +
11296 + return r;
11297 +}
11298 +EXPORT_SYMBOL(dsi_vc_dcs_write);
11299 +
11300 +int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen)
11301 +{
11302 + u32 val;
11303 + u8 dt;
11304 + int r;
11305 +
11306 + if (dsi.debug_read)
11307 + DSSDBG("dsi_vc_dcs_read(ch%d, dcs_cmd %u)\n", channel, dcs_cmd);
11308 +
11309 + r = dsi_vc_send_short(channel, DSI_DT_DCS_READ, dcs_cmd, 0);
11310 + if (r)
11311 + return r;
11312 +
11313 + r = dsi_vc_send_bta_sync(channel);
11314 + if (r)
11315 + return r;
11316 +
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");
11320 + return -EIO;
11321 + }
11322 +
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);
11330 + return -EIO;
11331 +
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);
11336 +
11337 + if (buflen < 1)
11338 + return -EIO;
11339 +
11340 + buf[0] = data;
11341 +
11342 + return 1;
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);
11347 +
11348 + if (buflen < 2)
11349 + return -EIO;
11350 +
11351 + buf[0] = data & 0xff;
11352 + buf[1] = (data >> 8) & 0xff;
11353 +
11354 + return 2;
11355 + } else if (dt == DSI_DT_RX_DCS_LONG_READ) {
11356 + int w;
11357 + int len = FLD_GET(val, 23, 8);
11358 + if (dsi.debug_read)
11359 + DSSDBG("\tDCS long response, len %d\n", len);
11360 +
11361 + if (len > buflen)
11362 + return -EIO;
11363 +
11364 + /* two byte checksum ends the packet, not included in len */
11365 + for (w = 0; w < len + 2;) {
11366 + int b;
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);
11374 +
11375 + for (b = 0; b < 4; ++b) {
11376 + if (w < len)
11377 + buf[w] = (val >> (b * 8)) & 0xff;
11378 + /* we discard the 2 byte checksum */
11379 + ++w;
11380 + }
11381 + }
11382 +
11383 + return len;
11384 +
11385 + } else {
11386 + DSSERR("\tunknown datatype 0x%02x\n", dt);
11387 + return -EIO;
11388 + }
11389 +}
11390 +EXPORT_SYMBOL(dsi_vc_dcs_read);
11391 +
11392 +
11393 +int dsi_vc_set_max_rx_packet_size(int channel, u16 len)
11394 +{
11395 + return dsi_vc_send_short(channel, DSI_DT_SET_MAX_RET_PKG_SIZE,
11396 + len, 0);
11397 +}
11398 +EXPORT_SYMBOL(dsi_vc_set_max_rx_packet_size);
11399 +
11400 +
11401 +static int dsi_set_lp_rx_timeout(int ns, int x4, int x16)
11402 +{
11403 + u32 r;
11404 + unsigned long fck;
11405 + int ticks;
11406 +
11407 + /* ticks in DSI_FCK */
11408 +
11409 + fck = dsi_fclk_rate();
11410 + ticks = (fck / 1000 / 1000) * ns / 1000;
11411 +
11412 + if (ticks > 0x1fff) {
11413 + DSSERR("LP_TX_TO too high\n");
11414 + return -EINVAL;
11415 + }
11416 +
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);
11423 +
11424 + DSSDBG("LP_RX_TO %ld ns (%#x ticks)\n",
11425 + (ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1) * 1000) /
11426 + (fck / 1000 / 1000),
11427 + ticks);
11428 +
11429 + return 0;
11430 +}
11431 +
11432 +static int dsi_set_ta_timeout(int ns, int x8, int x16)
11433 +{
11434 + u32 r;
11435 + unsigned long fck;
11436 + int ticks;
11437 +
11438 + /* ticks in DSI_FCK */
11439 +
11440 + fck = dsi_fclk_rate();
11441 + ticks = (fck / 1000 / 1000) * ns / 1000;
11442 +
11443 + if (ticks > 0x1fff) {
11444 + DSSERR("TA_TO too high\n");
11445 + return -EINVAL;
11446 + }
11447 +
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);
11454 +
11455 + DSSDBG("TA_TO %ld ns (%#x ticks)\n",
11456 + (ticks * (x16 ? 16 : 1) * (x8 ? 8 : 1) * 1000) /
11457 + (fck / 1000 / 1000),
11458 + ticks);
11459 +
11460 + return 0;
11461 +}
11462 +
11463 +static int dsi_set_stop_state_counter(int ns, int x4, int x16)
11464 +{
11465 + u32 r;
11466 + unsigned long fck;
11467 + int ticks;
11468 +
11469 + /* ticks in DSI_FCK */
11470 +
11471 + fck = dsi_fclk_rate();
11472 + ticks = (fck / 1000 / 1000) * ns / 1000;
11473 +
11474 + if (ticks > 0x1fff) {
11475 + DSSERR("STOP_STATE_COUNTER_IO too high\n");
11476 + return -EINVAL;
11477 + }
11478 +
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);
11485 +
11486 + DSSDBG("STOP_STATE_COUNTER %ld ns (%#x ticks)\n",
11487 + (ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1) * 1000) /
11488 + (fck / 1000 / 1000),
11489 + ticks);
11490 +
11491 + return 0;
11492 +}
11493 +
11494 +static int dsi_set_hs_tx_timeout(int ns, int x4, int x16)
11495 +{
11496 + u32 r;
11497 + unsigned long fck;
11498 + int ticks;
11499 +
11500 + /* ticks in TxByteClkHS */
11501 +
11502 + fck = dsi.ddr_clk / 4;
11503 + ticks = (fck / 1000 / 1000) * ns / 1000;
11504 +
11505 + if (ticks > 0x1fff) {
11506 + DSSERR("HS_TX_TO too high\n");
11507 + return -EINVAL;
11508 + }
11509 +
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);
11516 +
11517 + DSSDBG("HS_TX_TO %ld ns (%#x ticks)\n",
11518 + (ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1) * 1000) /
11519 + (fck / 1000 / 1000),
11520 + ticks);
11521 +
11522 + return 0;
11523 +}
11524 +static int dsi_proto_config(struct omap_dss_device *dssdev)
11525 +{
11526 + u32 r;
11527 + int buswidth = 0;
11528 + int div;
11529 +
11530 + dsi_config_tx_fifo(DSI_FIFO_SIZE_128,
11531 + DSI_FIFO_SIZE_0,
11532 + DSI_FIFO_SIZE_0,
11533 + DSI_FIFO_SIZE_0);
11534 +
11535 + dsi_config_rx_fifo(DSI_FIFO_SIZE_128,
11536 + DSI_FIFO_SIZE_0,
11537 + DSI_FIFO_SIZE_0,
11538 + DSI_FIFO_SIZE_0);
11539 +
11540 + /* XXX what values for the timeouts? */
11541 + dsi_set_stop_state_counter(1000, 0, 0);
11542 +
11543 + dsi_set_ta_timeout(50000, 1, 1);
11544 +
11545 + /* 3000ns * 16 */
11546 + dsi_set_lp_rx_timeout(3000, 0, 1);
11547 +
11548 + /* 10000ns * 4 */
11549 + dsi_set_hs_tx_timeout(10000, 1, 0);
11550 +
11551 + switch (dssdev->ctrl.pixel_size) {
11552 + case 16:
11553 + buswidth = 0;
11554 + break;
11555 + case 18:
11556 + buswidth = 1;
11557 + break;
11558 + case 24:
11559 + buswidth = 2;
11560 + break;
11561 + default:
11562 + BUG();
11563 + }
11564 +
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 */
11569 +
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 */
11579 +
11580 + dsi_write_reg(DSI_CTRL, r);
11581 +
11582 + dsi_vc_initial_config(0);
11583 +
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;
11589 +
11590 + return 0;
11591 +}
11592 +
11593 +static void dsi_proto_timings(struct omap_dss_device *dssdev)
11594 +{
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;
11602 + u32 r;
11603 +
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);
11610 +
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);
11615 +
11616 + r = dsi_read_reg(DSI_DSIPHY_CFG2);
11617 + tclk_prepare = FLD_GET(r, 7, 0);
11618 +
11619 + /* min 8*UI */
11620 + tclk_pre = 20;
11621 + /* min 60ns + 52*UI */
11622 + tclk_post = ns2ddr(60) + 26;
11623 +
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)
11627 + ths_eot = 2;
11628 + else
11629 + ths_eot = 4;
11630 +
11631 + ddr_clk_pre = DIV_ROUND_UP(tclk_pre + tlpx + tclk_zero + tclk_prepare,
11632 + 4);
11633 + ddr_clk_post = DIV_ROUND_UP(tclk_post + tclk_trail, 4) + ths_eot;
11634 +
11635 + BUG_ON(ddr_clk_pre == 0 || ddr_clk_pre > 255);
11636 + BUG_ON(ddr_clk_post == 0 || ddr_clk_post > 255);
11637 +
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);
11642 +
11643 + DSSDBG("ddr_clk_pre %u, ddr_clk_post %u\n",
11644 + ddr_clk_pre,
11645 + ddr_clk_post);
11646 +
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);
11650 +
11651 + exit_hs_mode_lat = DIV_ROUND_UP(ths_trail + ths_exit, 4) + 1 + ths_eot;
11652 +
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);
11656 +
11657 + DSSDBG("enter_hs_mode_lat %u, exit_hs_mode_lat %u\n",
11658 + enter_hs_mode_lat, exit_hs_mode_lat);
11659 +}
11660 +
11661 +
11662 +#define DSI_DECL_VARS \
11663 + int __dsi_cb = 0; u32 __dsi_cv = 0;
11664 +
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; \
11670 + }
11671 +
11672 +#define DSI_PUSH(ch, data) \
11673 + do { \
11674 + __dsi_cv |= (data) << (__dsi_cb * 8); \
11675 + /*DSSDBG("cv = %#010x, cb = %d\n", __dsi_cv, __dsi_cb);*/ \
11676 + if (++__dsi_cb > 3) \
11677 + DSI_FLUSH(ch); \
11678 + } while (0)
11679 +
11680 +static int dsi_update_screen_l4(struct omap_dss_device *dssdev,
11681 + int x, int y, int w, int h)
11682 +{
11683 + /* Note: supports only 24bit colors in 32bit container */
11684 + int first = 1;
11685 + int fifo_stalls = 0;
11686 + int max_dsi_packet_size;
11687 + int max_data_per_packet;
11688 + int max_pixels_per_packet;
11689 + int pixels_left;
11690 + int bytespp = dssdev->ctrl.pixel_size / 8;
11691 + int scr_width;
11692 + u32 __iomem *data;
11693 + int start_offset;
11694 + int horiz_inc;
11695 + int current_x;
11696 + struct omap_overlay *ovl;
11697 +
11698 + debug_irq = 0;
11699 +
11700 + DSSDBG("dsi_update_screen_l4 (%d,%d %dx%d)\n",
11701 + x, y, w, h);
11702 +
11703 + ovl = dssdev->manager->overlays[0];
11704 +
11705 + if (ovl->info.color_mode != OMAP_DSS_COLOR_RGB24U)
11706 + return -EINVAL;
11707 +
11708 + if (dssdev->ctrl.pixel_size != 24)
11709 + return -EINVAL;
11710 +
11711 + scr_width = ovl->info.screen_width;
11712 + data = ovl->info.vaddr;
11713 +
11714 + start_offset = scr_width * y + x;
11715 + horiz_inc = scr_width - w;
11716 + current_x = x;
11717 +
11718 + /* We need header(4) + DCSCMD(1) + pixels(numpix*bytespp) bytes
11719 + * in fifo */
11720 +
11721 + /* When using CPU, max long packet size is TX buffer size */
11722 + max_dsi_packet_size = dsi.vc[0].fifo_size * 32 * 4;
11723 +
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; */
11727 +
11728 + max_data_per_packet = max_dsi_packet_size - 4 - 1;
11729 +
11730 + max_pixels_per_packet = max_data_per_packet / bytespp;
11731 +
11732 + DSSDBG("max_pixels_per_packet %d\n", max_pixels_per_packet);
11733 +
11734 + pixels_left = w * h;
11735 +
11736 + DSSDBG("total pixels %d\n", pixels_left);
11737 +
11738 + data += start_offset;
11739 +
11740 + while (pixels_left > 0) {
11741 + /* 0x2c = write_memory_start */
11742 + /* 0x3c = write_memory_continue */
11743 + u8 dcs_cmd = first ? 0x2c : 0x3c;
11744 + int pixels;
11745 + DSI_DECL_VARS;
11746 + first = 0;
11747 +
11748 +#if 1
11749 + /* using fifo not empty */
11750 + /* TX_FIFO_NOT_EMPTY */
11751 + while (FLD_GET(dsi_read_reg(DSI_VC_CTRL(0)), 5, 5)) {
11752 + udelay(1);
11753 + fifo_stalls++;
11754 + if (fifo_stalls > 0xfffff) {
11755 + DSSERR("fifo stalls overflow, pixels left %d\n",
11756 + pixels_left);
11757 + dsi_if_enable(0);
11758 + return -EIO;
11759 + }
11760 + }
11761 +#elif 1
11762 + /* using fifo emptiness */
11763 + while ((REG_GET(DSI_TX_FIFO_VC_EMPTINESS, 7, 0)+1)*4 <
11764 + max_dsi_packet_size) {
11765 + fifo_stalls++;
11766 + if (fifo_stalls > 0xfffff) {
11767 + DSSERR("fifo stalls overflow, pixels left %d\n",
11768 + pixels_left);
11769 + dsi_if_enable(0);
11770 + return -EIO;
11771 + }
11772 + }
11773 +#else
11774 + while ((REG_GET(DSI_TX_FIFO_VC_EMPTINESS, 7, 0)+1)*4 == 0) {
11775 + fifo_stalls++;
11776 + if (fifo_stalls > 0xfffff) {
11777 + DSSERR("fifo stalls overflow, pixels left %d\n",
11778 + pixels_left);
11779 + dsi_if_enable(0);
11780 + return -EIO;
11781 + }
11782 + }
11783 +#endif
11784 + pixels = min(max_pixels_per_packet, pixels_left);
11785 +
11786 + pixels_left -= pixels;
11787 +
11788 + dsi_vc_write_long_header(0, DSI_DT_DCS_LONG_WRITE,
11789 + 1 + pixels * bytespp, 0);
11790 +
11791 + DSI_PUSH(0, dcs_cmd);
11792 +
11793 + while (pixels-- > 0) {
11794 + u32 pix = __raw_readl(data++);
11795 +
11796 + DSI_PUSH(0, (pix >> 16) & 0xff);
11797 + DSI_PUSH(0, (pix >> 8) & 0xff);
11798 + DSI_PUSH(0, (pix >> 0) & 0xff);
11799 +
11800 + current_x++;
11801 + if (current_x == x+w) {
11802 + current_x = x;
11803 + data += horiz_inc;
11804 + }
11805 + }
11806 +
11807 + DSI_FLUSH(0);
11808 + }
11809 +
11810 + return 0;
11811 +}
11812 +
11813 +static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
11814 + u16 x, u16 y, u16 w, u16 h)
11815 +{
11816 + int bytespp = dssdev->ctrl.pixel_size / 8;
11817 + int len;
11818 + int total_len;
11819 + int packet_payload;
11820 + int packet_len;
11821 + u32 l;
11822 + bool use_te_trigger;
11823 + const int channel = 0;
11824 +
11825 + use_te_trigger = dsi.te_enabled && !dsi.use_ext_te;
11826 +
11827 + if (dsi.update_mode != OMAP_DSS_UPDATE_AUTO)
11828 + DSSDBG("dsi_update_screen_dispc(%d,%d %dx%d)\n",
11829 + x, y, w, h);
11830 +
11831 + len = w * h * bytespp;
11832 +
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;
11837 +
11838 + packet_len = packet_payload + 1; /* 1 byte for DCS cmd */
11839 + total_len = (len / packet_payload) * packet_len;
11840 +
11841 + if (len % packet_payload)
11842 + total_len += (len % packet_payload) + 1;
11843 +
11844 + if (0)
11845 + dsi_vc_print_status(1);
11846 +
11847 + l = FLD_VAL(total_len, 23, 0); /* TE_SIZE */
11848 + dsi_write_reg(DSI_VC_TE(channel), l);
11849 +
11850 + dsi_vc_write_long_header(channel, DSI_DT_DCS_LONG_WRITE, packet_len, 0);
11851 +
11852 + if (use_te_trigger)
11853 + l = FLD_MOD(l, 1, 30, 30); /* TE_EN */
11854 + else
11855 + l = FLD_MOD(l, 1, 31, 31); /* TE_START */
11856 + dsi_write_reg(DSI_VC_TE(channel), l);
11857 +
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.
11863 + */
11864 + dispc_disable_sidle();
11865 +
11866 + dss_start_update(dssdev);
11867 +
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 */
11872 +
11873 + dsi_vc_send_bta(channel);
11874 + }
11875 +}
11876 +
11877 +static void dsi_framedone_irq_callback(void *data, u32 mask)
11878 +{
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.
11882 + */
11883 +
11884 + /* SIDLEMODE back to smart-idle */
11885 + dispc_enable_sidle();
11886 +
11887 + dsi.framedone_received = true;
11888 + wake_up(&dsi.waitqueue);
11889 +}
11890 +
11891 +static void dsi_set_update_region(struct omap_dss_device *dssdev,
11892 + u16 x, u16 y, u16 w, u16 h)
11893 +{
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);
11900 + } else {
11901 + dsi.update_region.x = x;
11902 + dsi.update_region.y = y;
11903 + dsi.update_region.w = w;
11904 + dsi.update_region.h = h;
11905 + }
11906 +
11907 + dsi.update_region.device = dssdev;
11908 + dsi.update_region.dirty = true;
11909 +
11910 + spin_unlock(&dsi.update_lock);
11911 +
11912 +}
11913 +
11914 +static void dsi_start_auto_update(struct omap_dss_device *dssdev)
11915 +{
11916 + u16 w, h;
11917 + int i;
11918 +
11919 + DSSDBG("starting auto update\n");
11920 +
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;
11929 + }
11930 + dssdev->manager->apply(dssdev->manager);
11931 +
11932 + dssdev->get_resolution(dssdev, &w, &h);
11933 +
11934 + dsi_set_update_region(dssdev, 0, 0, w, h);
11935 +
11936 + dsi_perf_mark_start_auto();
11937 +
11938 + wake_up(&dsi.waitqueue);
11939 +}
11940 +
11941 +static int dsi_set_te(struct omap_dss_device *dssdev, bool enable)
11942 +{
11943 + int r;
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 */
11947 + msleep(100);
11948 + return r;
11949 +}
11950 +
11951 +static void dsi_handle_framedone(void)
11952 +{
11953 + int r;
11954 + const int channel = 0;
11955 + bool use_te_trigger;
11956 +
11957 + use_te_trigger = dsi.te_enabled && !dsi.use_ext_te;
11958 +
11959 + if (dsi.update_mode != OMAP_DSS_UPDATE_AUTO)
11960 + DSSDBG("FRAMEDONE\n");
11961 +
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 */
11965 + }
11966 +
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
11970 + * trigger.
11971 + *
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
11975 + * transfer. */
11976 + r = dsi_vc_send_bta_sync(channel);
11977 + if (r)
11978 + DSSERR("BTA after framedone failed\n");
11979 +
11980 +#ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC
11981 + dispc_fake_vsync_irq();
11982 +#endif
11983 +}
11984 +
11985 +static int dsi_update_thread(void *data)
11986 +{
11987 + unsigned long timeout;
11988 + struct omap_dss_device *device;
11989 + u16 x, y, w, h;
11990 +
11991 + while (1) {
11992 + bool sched;
11993 +
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());
11999 +
12000 + if (kthread_should_stop())
12001 + break;
12002 +
12003 + dsi_bus_lock();
12004 +
12005 + if (dsi.update_mode == OMAP_DSS_UPDATE_DISABLED ||
12006 + kthread_should_stop()) {
12007 + dsi_bus_unlock();
12008 + break;
12009 + }
12010 +
12011 + dsi_perf_mark_setup();
12012 +
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);
12018 + }
12019 +
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;
12025 +
12026 + if (device->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
12027 +
12028 + if (dsi.update_mode == OMAP_DSS_UPDATE_MANUAL) {
12029 + dss_setup_partial_planes(device,
12030 + &x, &y, &w, &h);
12031 +#if 1
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 */
12036 + if (w & 1) {
12037 + u16 dw, dh;
12038 + device->get_resolution(device,
12039 + &dw, &dh);
12040 + if (x + w == dw)
12041 + x &= ~1;
12042 + ++w;
12043 +
12044 + dss_setup_partial_planes(device,
12045 + &x, &y, &w, &h);
12046 + }
12047 +#endif
12048 + }
12049 +
12050 + dispc_set_lcd_size(w, h);
12051 + }
12052 +
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);
12059 + }
12060 +
12061 + dsi_perf_mark_start();
12062 +
12063 + if (device->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
12064 + dsi_vc_config_vp(0);
12065 +
12066 + if (dsi.te_enabled && dsi.use_ext_te)
12067 + device->driver->wait_for_te(device);
12068 +
12069 + dsi.framedone_received = false;
12070 +
12071 + dsi_update_screen_dispc(device, x, y, w, h);
12072 +
12073 + /* wait for framedone */
12074 + timeout = msecs_to_jiffies(1000);
12075 + timeout = wait_event_timeout(dsi.waitqueue,
12076 + dsi.framedone_received == true,
12077 + timeout);
12078 +
12079 + if (timeout == 0) {
12080 + DSSERR("framedone timeout\n");
12081 + DSSERR("failed update %d,%d %dx%d\n",
12082 + x, y, w, h);
12083 +
12084 + dispc_enable_sidle();
12085 + dispc_enable_lcd_out(0);
12086 + } else {
12087 + dsi_handle_framedone();
12088 + dsi_perf_show("DISPC");
12089 + }
12090 + } else {
12091 + dsi_update_screen_l4(device, x, y, w, h);
12092 + dsi_perf_show("L4");
12093 + }
12094 +
12095 + sched = atomic_read(&dsi.bus_lock.count) < 0;
12096 +
12097 + complete_all(&dsi.update_completion);
12098 +
12099 + dsi_bus_unlock();
12100 +
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);
12105 + }
12106 +
12107 + DSSDBG("update thread exiting\n");
12108 +
12109 + return 0;
12110 +}
12111 +
12112 +
12113 +
12114 +/* Display funcs */
12115 +
12116 +static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
12117 +{
12118 + int r;
12119 +
12120 + r = omap_dispc_register_isr(dsi_framedone_irq_callback, NULL,
12121 + DISPC_IRQ_FRAMEDONE);
12122 + if (r) {
12123 + DSSERR("can't get FRAMEDONE irq\n");
12124 + return r;
12125 + }
12126 +
12127 + dispc_set_lcd_display_type(OMAP_DSS_LCD_DISPLAY_TFT);
12128 +
12129 + dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_DSI);
12130 + dispc_enable_fifohandcheck(1);
12131 +
12132 + dispc_set_tft_data_lines(dssdev->ctrl.pixel_size);
12133 +
12134 + {
12135 + struct omap_video_timings timings = {
12136 + .hsw = 1,
12137 + .hfp = 1,
12138 + .hbp = 1,
12139 + .vsw = 1,
12140 + .vfp = 0,
12141 + .vbp = 0,
12142 + };
12143 +
12144 + dispc_set_lcd_timings(&timings);
12145 + }
12146 +
12147 + return 0;
12148 +}
12149 +
12150 +static void dsi_display_uninit_dispc(struct omap_dss_device *dssdev)
12151 +{
12152 + omap_dispc_unregister_isr(dsi_framedone_irq_callback, NULL,
12153 + DISPC_IRQ_FRAMEDONE);
12154 +}
12155 +
12156 +static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
12157 +{
12158 + struct dsi_clock_info cinfo;
12159 + int r;
12160 +
12161 + _dsi_print_reset_status();
12162 +
12163 + r = dsi_pll_init(1, 0);
12164 + if (r)
12165 + goto err0;
12166 +
12167 + r = dsi_pll_calc_ddrfreq(dssdev->phy.dsi.ddr_clk_hz, &cinfo);
12168 + if (r)
12169 + goto err1;
12170 +
12171 + r = dsi_pll_program(&cinfo);
12172 + if (r)
12173 + goto err1;
12174 +
12175 + DSSDBG("PLL OK\n");
12176 +
12177 + r = dsi_complexio_init(dssdev);
12178 + if (r)
12179 + goto err1;
12180 +
12181 + _dsi_print_reset_status();
12182 +
12183 + dsi_proto_timings(dssdev);
12184 + dsi_set_lp_clk_divisor(dssdev);
12185 +
12186 + if (1)
12187 + _dsi_print_reset_status();
12188 +
12189 + r = dsi_proto_config(dssdev);
12190 + if (r)
12191 + goto err2;
12192 +
12193 + /* enable interface */
12194 + dsi_vc_enable(0, 1);
12195 + dsi_if_enable(1);
12196 + dsi_force_tx_stop_mode_io();
12197 +
12198 + if (dssdev->driver->enable) {
12199 + r = dssdev->driver->enable(dssdev);
12200 + if (r)
12201 + goto err3;
12202 + }
12203 +
12204 + /* enable high-speed after initial config */
12205 + dsi_vc_enable_hs(0, 1);
12206 +
12207 + return 0;
12208 +err3:
12209 + dsi_if_enable(0);
12210 +err2:
12211 + dsi_complexio_uninit();
12212 +err1:
12213 + dsi_pll_uninit();
12214 +err0:
12215 + return r;
12216 +}
12217 +
12218 +static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev)
12219 +{
12220 + if (dssdev->driver->disable)
12221 + dssdev->driver->disable(dssdev);
12222 +
12223 + dsi_complexio_uninit();
12224 + dsi_pll_uninit();
12225 +}
12226 +
12227 +static int dsi_core_init(void)
12228 +{
12229 + /* Autoidle */
12230 + REG_FLD_MOD(DSI_SYSCONFIG, 1, 0, 0);
12231 +
12232 + /* ENWAKEUP */
12233 + REG_FLD_MOD(DSI_SYSCONFIG, 1, 2, 2);
12234 +
12235 + /* SIDLEMODE smart-idle */
12236 + REG_FLD_MOD(DSI_SYSCONFIG, 2, 4, 3);
12237 +
12238 + _dsi_initialize_irq();
12239 +
12240 + return 0;
12241 +}
12242 +
12243 +static int dsi_display_enable(struct omap_dss_device *dssdev)
12244 +{
12245 + int r = 0;
12246 +
12247 + DSSDBG("dsi_display_enable\n");
12248 +
12249 + mutex_lock(&dsi.lock);
12250 + dsi_bus_lock();
12251 +
12252 + r = omap_dss_start_device(dssdev);
12253 + if (r) {
12254 + DSSERR("failed to start device\n");
12255 + goto err0;
12256 + }
12257 +
12258 + if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
12259 + DSSERR("dssdev already enabled\n");
12260 + r = -EINVAL;
12261 + goto err1;
12262 + }
12263 +
12264 + enable_clocks(1);
12265 + dsi_enable_pll_clock(1);
12266 +
12267 + r = _dsi_reset();
12268 + if (r)
12269 + goto err2;
12270 +
12271 + dsi_core_init();
12272 +
12273 + r = dsi_display_init_dispc(dssdev);
12274 + if (r)
12275 + goto err2;
12276 +
12277 + r = dsi_display_init_dsi(dssdev);
12278 + if (r)
12279 + goto err3;
12280 +
12281 + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
12282 +
12283 + dsi.use_ext_te = dssdev->phy.dsi.ext_te;
12284 + r = dsi_set_te(dssdev, dsi.te_enabled);
12285 + if (r)
12286 + goto err3;
12287 +
12288 + dsi.update_mode = dsi.user_update_mode;
12289 + if (dsi.update_mode == OMAP_DSS_UPDATE_AUTO)
12290 + dsi_start_auto_update(dssdev);
12291 +
12292 + dsi_bus_unlock();
12293 + mutex_unlock(&dsi.lock);
12294 +
12295 + return 0;
12296 +
12297 +err3:
12298 + dsi_display_uninit_dispc(dssdev);
12299 +err2:
12300 + enable_clocks(0);
12301 + dsi_enable_pll_clock(0);
12302 +err1:
12303 + omap_dss_stop_device(dssdev);
12304 +err0:
12305 + dsi_bus_unlock();
12306 + mutex_unlock(&dsi.lock);
12307 + DSSDBG("dsi_display_enable FAILED\n");
12308 + return r;
12309 +}
12310 +
12311 +static void dsi_display_disable(struct omap_dss_device *dssdev)
12312 +{
12313 + DSSDBG("dsi_display_disable\n");
12314 +
12315 + mutex_lock(&dsi.lock);
12316 + dsi_bus_lock();
12317 +
12318 + if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED ||
12319 + dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED)
12320 + goto end;
12321 +
12322 + dsi.update_mode = OMAP_DSS_UPDATE_DISABLED;
12323 + dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
12324 +
12325 + dsi_display_uninit_dispc(dssdev);
12326 +
12327 + dsi_display_uninit_dsi(dssdev);
12328 +
12329 + enable_clocks(0);
12330 + dsi_enable_pll_clock(0);
12331 +
12332 + omap_dss_stop_device(dssdev);
12333 +end:
12334 + dsi_bus_unlock();
12335 + mutex_unlock(&dsi.lock);
12336 +}
12337 +
12338 +static int dsi_display_suspend(struct omap_dss_device *dssdev)
12339 +{
12340 + DSSDBG("dsi_display_suspend\n");
12341 +
12342 + mutex_lock(&dsi.lock);
12343 + dsi_bus_lock();
12344 +
12345 + if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED ||
12346 + dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED)
12347 + goto end;
12348 +
12349 + dsi.update_mode = OMAP_DSS_UPDATE_DISABLED;
12350 + dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
12351 +
12352 + dsi_display_uninit_dispc(dssdev);
12353 +
12354 + dsi_display_uninit_dsi(dssdev);
12355 +
12356 + enable_clocks(0);
12357 + dsi_enable_pll_clock(0);
12358 +end:
12359 + dsi_bus_unlock();
12360 + mutex_unlock(&dsi.lock);
12361 +
12362 + return 0;
12363 +}
12364 +
12365 +static int dsi_display_resume(struct omap_dss_device *dssdev)
12366 +{
12367 + int r;
12368 +
12369 + DSSDBG("dsi_display_resume\n");
12370 +
12371 + mutex_lock(&dsi.lock);
12372 + dsi_bus_lock();
12373 +
12374 + if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) {
12375 + DSSERR("dssdev not suspended\n");
12376 + r = -EINVAL;
12377 + goto err0;
12378 + }
12379 +
12380 + enable_clocks(1);
12381 + dsi_enable_pll_clock(1);
12382 +
12383 + r = _dsi_reset();
12384 + if (r)
12385 + goto err1;
12386 +
12387 + dsi_core_init();
12388 +
12389 + r = dsi_display_init_dispc(dssdev);
12390 + if (r)
12391 + goto err1;
12392 +
12393 + r = dsi_display_init_dsi(dssdev);
12394 + if (r)
12395 + goto err2;
12396 +
12397 + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
12398 +
12399 + r = dsi_set_te(dssdev, dsi.te_enabled);
12400 + if (r)
12401 + goto err2;
12402 +
12403 + dsi.update_mode = dsi.user_update_mode;
12404 + if (dsi.update_mode == OMAP_DSS_UPDATE_AUTO)
12405 + dsi_start_auto_update(dssdev);
12406 +
12407 + dsi_bus_unlock();
12408 + mutex_unlock(&dsi.lock);
12409 +
12410 + return 0;
12411 +
12412 +err2:
12413 + dsi_display_uninit_dispc(dssdev);
12414 +err1:
12415 + enable_clocks(0);
12416 + dsi_enable_pll_clock(0);
12417 +err0:
12418 + dsi_bus_unlock();
12419 + mutex_unlock(&dsi.lock);
12420 + DSSDBG("dsi_display_resume FAILED\n");
12421 + return r;
12422 +}
12423 +
12424 +static int dsi_display_update(struct omap_dss_device *dssdev,
12425 + u16 x, u16 y, u16 w, u16 h)
12426 +{
12427 + int r = 0;
12428 + u16 dw, dh;
12429 +
12430 + DSSDBG("dsi_display_update(%d,%d %dx%d)\n", x, y, w, h);
12431 +
12432 + mutex_lock(&dsi.lock);
12433 +
12434 + if (dsi.update_mode != OMAP_DSS_UPDATE_MANUAL)
12435 + goto end;
12436 +
12437 + if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
12438 + goto end;
12439 +
12440 + dssdev->get_resolution(dssdev, &dw, &dh);
12441 +
12442 + if (x > dw || y > dh)
12443 + goto end;
12444 +
12445 + if (x + w > dw)
12446 + w = dw - x;
12447 +
12448 + if (y + h > dh)
12449 + h = dh - y;
12450 +
12451 + if (w == 0 || h == 0)
12452 + goto end;
12453 +
12454 + dsi_set_update_region(dssdev, x, y, w, h);
12455 +
12456 + wake_up(&dsi.waitqueue);
12457 +
12458 +end:
12459 + mutex_unlock(&dsi.lock);
12460 +
12461 + return r;
12462 +}
12463 +
12464 +static int dsi_display_sync(struct omap_dss_device *dssdev)
12465 +{
12466 + bool wait;
12467 +
12468 + DSSDBG("dsi_display_sync()\n");
12469 +
12470 + mutex_lock(&dsi.lock);
12471 + dsi_bus_lock();
12472 +
12473 + if (dsi.update_mode == OMAP_DSS_UPDATE_MANUAL &&
12474 + dsi.update_region.dirty) {
12475 + INIT_COMPLETION(dsi.update_completion);
12476 + wait = true;
12477 + } else {
12478 + wait = false;
12479 + }
12480 +
12481 + dsi_bus_unlock();
12482 + mutex_unlock(&dsi.lock);
12483 +
12484 + if (wait)
12485 + wait_for_completion_interruptible(&dsi.update_completion);
12486 +
12487 + DSSDBG("dsi_display_sync() done\n");
12488 + return 0;
12489 +}
12490 +
12491 +static int dsi_display_set_update_mode(struct omap_dss_device *dssdev,
12492 + enum omap_dss_update_mode mode)
12493 +{
12494 + DSSDBGF("%d", mode);
12495 +
12496 + mutex_lock(&dsi.lock);
12497 + dsi_bus_lock();
12498 +
12499 + if (dsi.update_mode != mode) {
12500 + dsi.user_update_mode = mode;
12501 + dsi.update_mode = mode;
12502 +
12503 + if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE &&
12504 + mode == OMAP_DSS_UPDATE_AUTO)
12505 + dsi_start_auto_update(dssdev);
12506 + }
12507 +
12508 + dsi_bus_unlock();
12509 + mutex_unlock(&dsi.lock);
12510 +
12511 + return 0;
12512 +}
12513 +
12514 +static enum omap_dss_update_mode dsi_display_get_update_mode(
12515 + struct omap_dss_device *dssdev)
12516 +{
12517 + return dsi.update_mode;
12518 +}
12519 +
12520 +
12521 +static int dsi_display_enable_te(struct omap_dss_device *dssdev, bool enable)
12522 +{
12523 + int r = 0;
12524 +
12525 + DSSDBGF("%d", enable);
12526 +
12527 + if (!dssdev->driver->enable_te)
12528 + return -ENOENT;
12529 +
12530 + dsi_bus_lock();
12531 +
12532 + dsi.te_enabled = enable;
12533 +
12534 + if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
12535 + goto end;
12536 +
12537 + r = dsi_set_te(dssdev, enable);
12538 +end:
12539 + dsi_bus_unlock();
12540 +
12541 + return r;
12542 +}
12543 +
12544 +static int dsi_display_get_te(struct omap_dss_device *dssdev)
12545 +{
12546 + return dsi.te_enabled;
12547 +}
12548 +
12549 +static int dsi_display_set_rotate(struct omap_dss_device *dssdev, u8 rotate)
12550 +{
12551 +
12552 + DSSDBGF("%d", rotate);
12553 +
12554 + if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate)
12555 + return -EINVAL;
12556 +
12557 + dsi_bus_lock();
12558 + dssdev->driver->set_rotate(dssdev, rotate);
12559 + if (dsi.update_mode == OMAP_DSS_UPDATE_AUTO) {
12560 + u16 w, h;
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);
12565 + }
12566 + dsi_bus_unlock();
12567 +
12568 + return 0;
12569 +}
12570 +
12571 +static u8 dsi_display_get_rotate(struct omap_dss_device *dssdev)
12572 +{
12573 + if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate)
12574 + return 0;
12575 +
12576 + return dssdev->driver->get_rotate(dssdev);
12577 +}
12578 +
12579 +static int dsi_display_set_mirror(struct omap_dss_device *dssdev, bool mirror)
12580 +{
12581 + DSSDBGF("%d", mirror);
12582 +
12583 + if (!dssdev->driver->set_mirror || !dssdev->driver->get_mirror)
12584 + return -EINVAL;
12585 +
12586 + dsi_bus_lock();
12587 + dssdev->driver->set_mirror(dssdev, mirror);
12588 + dsi_bus_unlock();
12589 +
12590 + return 0;
12591 +}
12592 +
12593 +static bool dsi_display_get_mirror(struct omap_dss_device *dssdev)
12594 +{
12595 + if (!dssdev->driver->set_mirror || !dssdev->driver->get_mirror)
12596 + return 0;
12597 +
12598 + return dssdev->driver->get_mirror(dssdev);
12599 +}
12600 +
12601 +static int dsi_display_run_test(struct omap_dss_device *dssdev, int test_num)
12602 +{
12603 + int r;
12604 +
12605 + if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
12606 + return -EIO;
12607 +
12608 + DSSDBGF("%d", test_num);
12609 +
12610 + dsi_bus_lock();
12611 +
12612 + /* run test first in low speed mode */
12613 + dsi_vc_enable_hs(0, 0);
12614 +
12615 + if (dssdev->driver->run_test) {
12616 + r = dssdev->driver->run_test(dssdev, test_num);
12617 + if (r)
12618 + goto end;
12619 + }
12620 +
12621 + /* then in high speed */
12622 + dsi_vc_enable_hs(0, 1);
12623 +
12624 + if (dssdev->driver->run_test) {
12625 + r = dssdev->driver->run_test(dssdev, test_num);
12626 + if (r)
12627 + goto end;
12628 + }
12629 +
12630 +end:
12631 + dsi_vc_enable_hs(0, 1);
12632 +
12633 + dsi_bus_unlock();
12634 +
12635 + return r;
12636 +}
12637 +
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)
12641 +{
12642 + int r;
12643 +
12644 + DSSDBGF("");
12645 +
12646 + if (!dssdev->driver->memory_read)
12647 + return -EINVAL;
12648 +
12649 + if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
12650 + return -EIO;
12651 +
12652 + dsi_bus_lock();
12653 +
12654 + r = dssdev->driver->memory_read(dssdev, buf, size,
12655 + x, y, w, h);
12656 +
12657 + dsi_bus_unlock();
12658 +
12659 + return r;
12660 +}
12661 +
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)
12665 +{
12666 + unsigned burst_size_bytes;
12667 +
12668 + *burst_size = OMAP_DSS_BURST_16x32;
12669 + burst_size_bytes = 16 * 32 / 8;
12670 +
12671 + *fifo_high = fifo_size - burst_size_bytes;
12672 + *fifo_low = 0;
12673 +}
12674 +
12675 +int dsi_init_display(struct omap_dss_device *dssdev)
12676 +{
12677 + DSSDBG("DSI init\n");
12678 +
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;
12689 +
12690 + dssdev->get_rotate = dsi_display_get_rotate;
12691 + dssdev->set_rotate = dsi_display_set_rotate;
12692 +
12693 + dssdev->get_mirror = dsi_display_get_mirror;
12694 + dssdev->set_mirror = dsi_display_set_mirror;
12695 +
12696 + dssdev->run_test = dsi_display_run_test;
12697 + dssdev->memory_read = dsi_display_memory_read;
12698 +
12699 + dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
12700 +
12701 + dsi.vc[0].dssdev = dssdev;
12702 + dsi.vc[1].dssdev = dssdev;
12703 +
12704 + return 0;
12705 +}
12706 +
12707 +int dsi_init(struct platform_device *pdev)
12708 +{
12709 + u32 rev;
12710 + struct sched_param param = {
12711 + .sched_priority = MAX_USER_RT_PRIO-1
12712 + };
12713 +
12714 + spin_lock_init(&dsi.errors_lock);
12715 + dsi.errors = 0;
12716 +
12717 + /* XXX fail properly */
12718 +
12719 + init_completion(&dsi.bta_completion);
12720 + init_completion(&dsi.update_completion);
12721 +
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);
12726 + }
12727 + sched_setscheduler(dsi.thread, SCHED_FIFO, &param);
12728 +
12729 + init_waitqueue_head(&dsi.waitqueue);
12730 + spin_lock_init(&dsi.update_lock);
12731 +
12732 + mutex_init(&dsi.lock);
12733 + mutex_init(&dsi.bus_lock);
12734 +
12735 + dsi.update_mode = OMAP_DSS_UPDATE_DISABLED;
12736 + dsi.user_update_mode = OMAP_DSS_UPDATE_DISABLED;
12737 +
12738 + dsi.base = ioremap(DSI_BASE, DSI_SZ_REGS);
12739 + if (!dsi.base) {
12740 + DSSERR("can't ioremap DSI\n");
12741 + return -ENOMEM;
12742 + }
12743 +
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);
12749 + }
12750 +
12751 + enable_clocks(1);
12752 +
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));
12756 +
12757 + enable_clocks(0);
12758 +
12759 + wake_up_process(dsi.thread);
12760 +
12761 + return 0;
12762 +}
12763 +
12764 +void dsi_exit(void)
12765 +{
12766 + kthread_stop(dsi.thread);
12767 +
12768 + regulator_put(dsi.vdds_dsi_reg);
12769 +
12770 + iounmap(dsi.base);
12771 +
12772 + DSSDBG("omap_dsi_exit\n");
12773 +}
12774 +
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
12778 --- /dev/null
12779 +++ b/drivers/video/omap2/dss/dss.c
12780 @@ -0,0 +1,347 @@
12781 +/*
12782 + * linux/drivers/video/omap2/dss/dss.c
12783 + *
12784 + * Copyright (C) 2009 Nokia Corporation
12785 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
12786 + *
12787 + * Some code and ideas taken from drivers/video/omap/ driver
12788 + * by Imre Deak.
12789 + *
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.
12793 + *
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
12797 + * more details.
12798 + *
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/>.
12801 + */
12802 +
12803 +#define DSS_SUBSYS_NAME "DSS"
12804 +
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>
12811 +
12812 +#include <mach/display.h>
12813 +#include "dss.h"
12814 +
12815 +#define DSS_BASE 0x48050000
12816 +
12817 +#define DSS_SZ_REGS SZ_512
12818 +
12819 +struct dss_reg {
12820 + u16 idx;
12821 +};
12822 +
12823 +#define DSS_REG(idx) ((const struct dss_reg) { idx })
12824 +
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)
12833 +
12834 +#define REG_GET(idx, start, end) \
12835 + FLD_GET(dss_read_reg(idx), start, end)
12836 +
12837 +#define REG_FLD_MOD(idx, val, start, end) \
12838 + dss_write_reg(idx, FLD_MOD(dss_read_reg(idx), val, start, end))
12839 +
12840 +static struct {
12841 + void __iomem *base;
12842 +
12843 + u32 ctx[DSS_SZ_REGS / sizeof(u32)];
12844 +} dss;
12845 +
12846 +static int _omap_dss_wait_reset(void);
12847 +
12848 +static inline void dss_write_reg(const struct dss_reg idx, u32 val)
12849 +{
12850 + __raw_writel(val, dss.base + idx.idx);
12851 +}
12852 +
12853 +static inline u32 dss_read_reg(const struct dss_reg idx)
12854 +{
12855 + return __raw_readl(dss.base + idx.idx);
12856 +}
12857 +
12858 +#define SR(reg) \
12859 + dss.ctx[(DSS_##reg).idx / sizeof(u32)] = dss_read_reg(DSS_##reg)
12860 +#define RR(reg) \
12861 + dss_write_reg(DSS_##reg, dss.ctx[(DSS_##reg).idx / sizeof(u32)])
12862 +
12863 +void dss_save_context(void)
12864 +{
12865 + if (cpu_is_omap24xx())
12866 + return;
12867 +
12868 + SR(SYSCONFIG);
12869 + SR(CONTROL);
12870 +
12871 +#ifdef CONFIG_OMAP2_DSS_SDI
12872 + SR(SDI_CONTROL);
12873 + SR(PLL_CONTROL);
12874 +#endif
12875 +}
12876 +
12877 +void dss_restore_context(void)
12878 +{
12879 + if (_omap_dss_wait_reset())
12880 + DSSERR("DSS not coming out of reset after sleep\n");
12881 +
12882 + RR(SYSCONFIG);
12883 + RR(CONTROL);
12884 +
12885 +#ifdef CONFIG_OMAP2_DSS_SDI
12886 + RR(SDI_CONTROL);
12887 + RR(PLL_CONTROL);
12888 +#endif
12889 +}
12890 +
12891 +#undef SR
12892 +#undef RR
12893 +
12894 +void dss_sdi_init(u8 datapairs)
12895 +{
12896 + u32 l;
12897 +
12898 + BUG_ON(datapairs > 3 || datapairs < 1);
12899 +
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);
12905 +
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);
12911 +}
12912 +
12913 +void dss_sdi_enable(void)
12914 +{
12915 + dispc_pck_free_enable(1);
12916 +
12917 + /* Reset SDI PLL */
12918 + REG_FLD_MOD(DSS_PLL_CONTROL, 1, 18, 18); /* SDI_PLL_SYSRESET */
12919 + udelay(1); /* wait 2x PCLK */
12920 +
12921 + /* Lock SDI PLL */
12922 + REG_FLD_MOD(DSS_PLL_CONTROL, 1, 28, 28); /* SDI_PLL_GOBIT */
12923 +
12924 + /* Waiting for PLL lock request to complete */
12925 + while (dss_read_reg(DSS_SDI_STATUS) & (1 << 6))
12926 + ;
12927 +
12928 + /* Clearing PLL_GO bit */
12929 + REG_FLD_MOD(DSS_PLL_CONTROL, 0, 28, 28);
12930 +
12931 + /* Waiting for PLL to lock */
12932 + while (!(dss_read_reg(DSS_SDI_STATUS) & (1 << 5)))
12933 + ;
12934 +
12935 + dispc_lcd_enable_signal(1);
12936 +
12937 + /* Waiting for SDI reset to complete */
12938 + while (!(dss_read_reg(DSS_SDI_STATUS) & (1 << 2)))
12939 + ;
12940 +}
12941 +
12942 +void dss_sdi_disable(void)
12943 +{
12944 + dispc_lcd_enable_signal(0);
12945 +
12946 + dispc_pck_free_enable(0);
12947 +
12948 + /* Reset SDI PLL */
12949 + REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */
12950 +}
12951 +
12952 +void dss_dump_regs(struct seq_file *s)
12953 +{
12954 +#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dss_read_reg(r))
12955 +
12956 + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
12957 +
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);
12966 +
12967 + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
12968 +#undef DUMPREG
12969 +}
12970 +
12971 +void dss_select_clk_source(bool dsi, bool dispc)
12972 +{
12973 + u32 r;
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);
12978 +}
12979 +
12980 +int dss_get_dsi_clk_source(void)
12981 +{
12982 + return FLD_GET(dss_read_reg(DSS_CONTROL), 1, 1);
12983 +}
12984 +
12985 +int dss_get_dispc_clk_source(void)
12986 +{
12987 + return FLD_GET(dss_read_reg(DSS_CONTROL), 0, 0);
12988 +}
12989 +
12990 +static irqreturn_t dss_irq_handler_omap2(int irq, void *arg)
12991 +{
12992 + dispc_irq_handler();
12993 +
12994 + return IRQ_HANDLED;
12995 +}
12996 +
12997 +static irqreturn_t dss_irq_handler_omap3(int irq, void *arg)
12998 +{
12999 + u32 irqstatus;
13000 +
13001 + irqstatus = dss_read_reg(DSS_IRQSTATUS);
13002 +
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();
13008 +#endif
13009 +
13010 + return IRQ_HANDLED;
13011 +}
13012 +
13013 +static int _omap_dss_wait_reset(void)
13014 +{
13015 + unsigned timeout = 1000;
13016 +
13017 + while (REG_GET(DSS_SYSSTATUS, 0, 0) == 0) {
13018 + udelay(1);
13019 + if (!--timeout) {
13020 + DSSERR("soft reset failed\n");
13021 + return -ENODEV;
13022 + }
13023 + }
13024 +
13025 + return 0;
13026 +}
13027 +
13028 +static int _omap_dss_reset(void)
13029 +{
13030 + /* Soft reset */
13031 + REG_FLD_MOD(DSS_SYSCONFIG, 1, 1, 1);
13032 + return _omap_dss_wait_reset();
13033 +}
13034 +
13035 +void dss_set_venc_output(enum omap_dss_venc_type type)
13036 +{
13037 + int l = 0;
13038 +
13039 + if (type == OMAP_DSS_VENC_TYPE_COMPOSITE)
13040 + l = 0;
13041 + else if (type == OMAP_DSS_VENC_TYPE_SVIDEO)
13042 + l = 1;
13043 + else
13044 + BUG();
13045 +
13046 + /* venc out selection. 0 = comp, 1 = svideo */
13047 + REG_FLD_MOD(DSS_CONTROL, l, 6, 6);
13048 +}
13049 +
13050 +void dss_set_dac_pwrdn_bgz(bool enable)
13051 +{
13052 + REG_FLD_MOD(DSS_CONTROL, enable, 5, 5); /* DAC Power-Down Control */
13053 +}
13054 +
13055 +int dss_init(bool skip_init)
13056 +{
13057 + int r;
13058 + u32 rev;
13059 +
13060 + dss.base = ioremap(DSS_BASE, DSS_SZ_REGS);
13061 + if (!dss.base) {
13062 + DSSERR("can't ioremap DSS\n");
13063 + r = -ENOMEM;
13064 + goto fail0;
13065 + }
13066 +
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);
13072 +
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.
13078 + */
13079 + msleep(50);
13080 +
13081 + _omap_dss_reset();
13082 + }
13083 +
13084 + /* autoidle */
13085 + REG_FLD_MOD(DSS_SYSCONFIG, 1, 0, 0);
13086 +
13087 + /* Select DPLL */
13088 + REG_FLD_MOD(DSS_CONTROL, 0, 0, 0);
13089 +
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 */
13094 +#endif
13095 +
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);
13101 +
13102 + if (r < 0) {
13103 + DSSERR("omap2 dss: request_irq failed\n");
13104 + goto fail1;
13105 + }
13106 +
13107 + dss_save_context();
13108 +
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));
13112 +
13113 + return 0;
13114 +
13115 +fail1:
13116 + iounmap(dss.base);
13117 +fail0:
13118 + return r;
13119 +}
13120 +
13121 +void dss_exit(void)
13122 +{
13123 + free_irq(INT_24XX_DSS_IRQ, NULL);
13124 +
13125 + iounmap(dss.base);
13126 +}
13127 +
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
13131 --- /dev/null
13132 +++ b/drivers/video/omap2/dss/dss.h
13133 @@ -0,0 +1,356 @@
13134 +/*
13135 + * linux/drivers/video/omap2/dss/dss.h
13136 + *
13137 + * Copyright (C) 2009 Nokia Corporation
13138 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
13139 + *
13140 + * Some code and ideas taken from drivers/video/omap/ driver
13141 + * by Imre Deak.
13142 + *
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.
13146 + *
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
13150 + * more details.
13151 + *
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/>.
13154 + */
13155 +
13156 +#ifndef __OMAP2_DSS_H
13157 +#define __OMAP2_DSS_H
13158 +
13159 +#ifdef CONFIG_OMAP2_DSS_DEBUG_SUPPORT
13160 +#define DEBUG
13161 +#endif
13162 +
13163 +#ifdef DEBUG
13164 +extern unsigned int dss_debug;
13165 +#ifdef DSS_SUBSYS_NAME
13166 +#define DSSDBG(format, ...) \
13167 + if (dss_debug) \
13168 + printk(KERN_DEBUG "omapdss " DSS_SUBSYS_NAME ": " format, \
13169 + ## __VA_ARGS__)
13170 +#else
13171 +#define DSSDBG(format, ...) \
13172 + if (dss_debug) \
13173 + printk(KERN_DEBUG "omapdss: " format, ## __VA_ARGS__)
13174 +#endif
13175 +
13176 +#ifdef DSS_SUBSYS_NAME
13177 +#define DSSDBGF(format, ...) \
13178 + if (dss_debug) \
13179 + printk(KERN_DEBUG "omapdss " DSS_SUBSYS_NAME \
13180 + ": %s(" format ")\n", \
13181 + __func__, \
13182 + ## __VA_ARGS__)
13183 +#else
13184 +#define DSSDBGF(format, ...) \
13185 + if (dss_debug) \
13186 + printk(KERN_DEBUG "omapdss: " \
13187 + ": %s(" format ")\n", \
13188 + __func__, \
13189 + ## __VA_ARGS__)
13190 +#endif
13191 +
13192 +#else /* DEBUG */
13193 +#define DSSDBG(format, ...)
13194 +#define DSSDBGF(format, ...)
13195 +#endif
13196 +
13197 +
13198 +#ifdef DSS_SUBSYS_NAME
13199 +#define DSSERR(format, ...) \
13200 + printk(KERN_ERR "omapdss " DSS_SUBSYS_NAME " error: " format, \
13201 + ## __VA_ARGS__)
13202 +#else
13203 +#define DSSERR(format, ...) \
13204 + printk(KERN_ERR "omapdss error: " format, ## __VA_ARGS__)
13205 +#endif
13206 +
13207 +#ifdef DSS_SUBSYS_NAME
13208 +#define DSSINFO(format, ...) \
13209 + printk(KERN_INFO "omapdss " DSS_SUBSYS_NAME ": " format, \
13210 + ## __VA_ARGS__)
13211 +#else
13212 +#define DSSINFO(format, ...) \
13213 + printk(KERN_INFO "omapdss: " format, ## __VA_ARGS__)
13214 +#endif
13215 +
13216 +#ifdef DSS_SUBSYS_NAME
13217 +#define DSSWARN(format, ...) \
13218 + printk(KERN_WARNING "omapdss " DSS_SUBSYS_NAME ": " format, \
13219 + ## __VA_ARGS__)
13220 +#else
13221 +#define DSSWARN(format, ...) \
13222 + printk(KERN_WARNING "omapdss: " format, ## __VA_ARGS__)
13223 +#endif
13224 +
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))
13232 +
13233 +#define DISPC_MAX_FCK 173000000
13234 +
13235 +enum omap_burst_size {
13236 + OMAP_DSS_BURST_4x32 = 0,
13237 + OMAP_DSS_BURST_8x32 = 1,
13238 + OMAP_DSS_BURST_16x32 = 2,
13239 +};
13240 +
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,
13245 +};
13246 +
13247 +enum dss_clock {
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,
13253 +};
13254 +
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;
13260 +
13261 + /* dividers */
13262 + u16 fck_div;
13263 + u16 lck_div;
13264 + u16 pck_div;
13265 +};
13266 +
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;
13276 +
13277 + /* dividers */
13278 + u16 regn;
13279 + u16 regm;
13280 + u16 regm3;
13281 + u16 regm4;
13282 +
13283 + u16 lck_div;
13284 + u16 pck_div;
13285 +
13286 + u8 highfreq;
13287 + bool use_dss2_fck;
13288 +};
13289 +
13290 +struct seq_file;
13291 +struct platform_device;
13292 +
13293 +/* core */
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);
13300 +
13301 +/* display */
13302 +int dss_suspend_all_devices(void);
13303 +int dss_resume_all_devices(void);
13304 +
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);
13314 +
13315 +/* manager */
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);
13322 +
13323 +/* overlay */
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);
13328 +#ifdef L4_EXAMPLE
13329 +void dss_overlay_setup_l4_manager(struct omap_overlay_manager *mgr);
13330 +#endif
13331 +void dss_recheck_connections(struct omap_dss_device *dssdev, bool force);
13332 +
13333 +/* DSS */
13334 +int dss_init(bool skip_init);
13335 +void dss_exit(void);
13336 +
13337 +void dss_save_context(void);
13338 +void dss_restore_context(void);
13339 +
13340 +void dss_dump_regs(struct seq_file *s);
13341 +
13342 +void dss_sdi_init(u8 datapairs);
13343 +void dss_sdi_enable(void);
13344 +void dss_sdi_disable(void);
13345 +
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);
13351 +
13352 +/* SDI */
13353 +int sdi_init(bool skip_init);
13354 +void sdi_exit(void);
13355 +int sdi_init_display(struct omap_dss_device *display);
13356 +
13357 +/* DSI */
13358 +int dsi_init(struct platform_device *pdev);
13359 +void dsi_exit(void);
13360 +
13361 +void dsi_dump_clocks(struct seq_file *s);
13362 +void dsi_dump_regs(struct seq_file *s);
13363 +
13364 +void dsi_save_context(void);
13365 +void dsi_restore_context(void);
13366 +
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);
13379 +
13380 +/* DPI */
13381 +int dpi_init(void);
13382 +void dpi_exit(void);
13383 +int dpi_init_display(struct omap_dss_device *dssdev);
13384 +
13385 +/* DISPC */
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);
13392 +
13393 +void dispc_save_context(void);
13394 +void dispc_restore_context(void);
13395 +
13396 +void dispc_enable_sidle(void);
13397 +void dispc_disable_sidle(void);
13398 +
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);
13403 +
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);
13411 +
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);
13418 +
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,
13425 + bool ilace,
13426 + enum omap_dss_rotation_type rotation_type,
13427 + u8 rotation, bool mirror,
13428 + u8 global_alpha);
13429 +
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);
13436 +
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);
13441 +
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,
13446 + u32 trans_key);
13447 +void dispc_get_trans_key(enum omap_channel ch,
13448 + enum omap_dss_trans_key_type *type,
13449 + u32 *trans_key);
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);
13454 +
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);
13468 +
13469 +
13470 +/* VENC */
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);
13475 +
13476 +/* RFBI */
13477 +int rfbi_init(void);
13478 +void rfbi_exit(void);
13479 +void rfbi_dump_regs(struct seq_file *s);
13480 +
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);
13488 +
13489 +#endif
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
13493 --- /dev/null
13494 +++ b/drivers/video/omap2/dss/manager.c
13495 @@ -0,0 +1,1487 @@
13496 +/*
13497 + * linux/drivers/video/omap2/dss/manager.c
13498 + *
13499 + * Copyright (C) 2009 Nokia Corporation
13500 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
13501 + *
13502 + * Some code and ideas taken from drivers/video/omap/ driver
13503 + * by Imre Deak.
13504 + *
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.
13508 + *
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
13512 + * more details.
13513 + *
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/>.
13516 + */
13517 +
13518 +#define DSS_SUBSYS_NAME "MANAGER"
13519 +
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>
13525 +
13526 +#include <mach/display.h>
13527 +#include <mach/cpu.h>
13528 +
13529 +#include "dss.h"
13530 +
13531 +static int num_managers;
13532 +static struct list_head manager_list;
13533 +
13534 +static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf)
13535 +{
13536 + return snprintf(buf, PAGE_SIZE, "%s\n", mgr->name);
13537 +}
13538 +
13539 +static ssize_t manager_display_show(struct omap_overlay_manager *mgr, char *buf)
13540 +{
13541 + return snprintf(buf, PAGE_SIZE, "%s\n",
13542 + mgr->device ? mgr->device->name : "<none>");
13543 +}
13544 +
13545 +static ssize_t manager_display_store(struct omap_overlay_manager *mgr,
13546 + const char *buf, size_t size)
13547 +{
13548 + int r = 0;
13549 + size_t len = size;
13550 + struct omap_dss_device *dssdev = NULL;
13551 +
13552 + int match(struct omap_dss_device *dssdev, void *data)
13553 + {
13554 + const char *str = data;
13555 + return sysfs_streq(dssdev->name, str);
13556 + }
13557 +
13558 + if (buf[size-1] == '\n')
13559 + --len;
13560 +
13561 + if (len > 0)
13562 + dssdev = omap_dss_find_device((void *)buf, match);
13563 +
13564 + if (len > 0 && dssdev == NULL)
13565 + return -EINVAL;
13566 +
13567 + if (dssdev)
13568 + DSSDBG("display %s found\n", dssdev->name);
13569 +
13570 + if (mgr->device) {
13571 + r = mgr->unset_device(mgr);
13572 + if (r) {
13573 + DSSERR("failed to unset display\n");
13574 + goto put_device;
13575 + }
13576 + }
13577 +
13578 + if (dssdev) {
13579 + r = mgr->set_device(mgr, dssdev);
13580 + if (r) {
13581 + DSSERR("failed to set manager\n");
13582 + goto put_device;
13583 + }
13584 +
13585 + r = mgr->apply(mgr);
13586 + if (r) {
13587 + DSSERR("failed to apply dispc config\n");
13588 + goto put_device;
13589 + }
13590 + }
13591 +
13592 +put_device:
13593 + if (dssdev)
13594 + omap_dss_put_device(dssdev);
13595 +
13596 + return r ? r : size;
13597 +}
13598 +
13599 +static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr,
13600 + char *buf)
13601 +{
13602 + return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.default_color);
13603 +}
13604 +
13605 +static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr,
13606 + const char *buf, size_t size)
13607 +{
13608 + struct omap_overlay_manager_info info;
13609 + u32 color;
13610 + int r;
13611 +
13612 + if (sscanf(buf, "%d", &color) != 1)
13613 + return -EINVAL;
13614 +
13615 + mgr->get_manager_info(mgr, &info);
13616 +
13617 + info.default_color = color;
13618 +
13619 + r = mgr->set_manager_info(mgr, &info);
13620 + if (r)
13621 + return r;
13622 +
13623 + r = mgr->apply(mgr);
13624 + if (r)
13625 + return r;
13626 +
13627 + return size;
13628 +}
13629 +
13630 +static const char *trans_key_type_str[] = {
13631 + "gfx-destination",
13632 + "video-source",
13633 +};
13634 +
13635 +static ssize_t manager_trans_key_type_show(struct omap_overlay_manager *mgr,
13636 + char *buf)
13637 +{
13638 + enum omap_dss_trans_key_type key_type;
13639 +
13640 + key_type = mgr->info.trans_key_type;
13641 + BUG_ON(key_type >= ARRAY_SIZE(trans_key_type_str));
13642 +
13643 + return snprintf(buf, PAGE_SIZE, "%s\n", trans_key_type_str[key_type]);
13644 +}
13645 +
13646 +static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr,
13647 + const char *buf, size_t size)
13648 +{
13649 + enum omap_dss_trans_key_type key_type;
13650 + struct omap_overlay_manager_info info;
13651 + int r;
13652 +
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]))
13656 + break;
13657 + }
13658 +
13659 + if (key_type == ARRAY_SIZE(trans_key_type_str))
13660 + return -EINVAL;
13661 +
13662 + mgr->get_manager_info(mgr, &info);
13663 +
13664 + info.trans_key_type = key_type;
13665 +
13666 + r = mgr->set_manager_info(mgr, &info);
13667 + if (r)
13668 + return r;
13669 +
13670 + r = mgr->apply(mgr);
13671 + if (r)
13672 + return r;
13673 +
13674 + return size;
13675 +}
13676 +
13677 +static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr,
13678 + char *buf)
13679 +{
13680 + return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.trans_key);
13681 +}
13682 +
13683 +static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr,
13684 + const char *buf, size_t size)
13685 +{
13686 + struct omap_overlay_manager_info info;
13687 + u32 key_value;
13688 + int r;
13689 +
13690 + if (sscanf(buf, "%d", &key_value) != 1)
13691 + return -EINVAL;
13692 +
13693 + mgr->get_manager_info(mgr, &info);
13694 +
13695 + info.trans_key = key_value;
13696 +
13697 + r = mgr->set_manager_info(mgr, &info);
13698 + if (r)
13699 + return r;
13700 +
13701 + r = mgr->apply(mgr);
13702 + if (r)
13703 + return r;
13704 +
13705 + return size;
13706 +}
13707 +
13708 +static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr,
13709 + char *buf)
13710 +{
13711 + return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.trans_enabled);
13712 +}
13713 +
13714 +static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr,
13715 + const char *buf, size_t size)
13716 +{
13717 + struct omap_overlay_manager_info info;
13718 + int enable;
13719 + int r;
13720 +
13721 + if (sscanf(buf, "%d", &enable) != 1)
13722 + return -EINVAL;
13723 +
13724 + mgr->get_manager_info(mgr, &info);
13725 +
13726 + info.trans_enabled = enable ? true : false;
13727 +
13728 + r = mgr->set_manager_info(mgr, &info);
13729 + if (r)
13730 + return r;
13731 +
13732 + r = mgr->apply(mgr);
13733 + if (r)
13734 + return r;
13735 +
13736 + return size;
13737 +}
13738 +
13739 +static ssize_t manager_alpha_blending_enabled_show(
13740 + struct omap_overlay_manager *mgr, char *buf)
13741 +{
13742 + return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.alpha_enabled);
13743 +}
13744 +
13745 +static ssize_t manager_alpha_blending_enabled_store(
13746 + struct omap_overlay_manager *mgr,
13747 + const char *buf, size_t size)
13748 +{
13749 + struct omap_overlay_manager_info info;
13750 + int enable;
13751 + int r;
13752 +
13753 + if (sscanf(buf, "%d", &enable) != 1)
13754 + return -EINVAL;
13755 +
13756 + mgr->get_manager_info(mgr, &info);
13757 +
13758 + info.alpha_enabled = enable ? true : false;
13759 +
13760 + r = mgr->set_manager_info(mgr, &info);
13761 + if (r)
13762 + return r;
13763 +
13764 + r = mgr->apply(mgr);
13765 + if (r)
13766 + return r;
13767 +
13768 + return size;
13769 +}
13770 +
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);
13775 +};
13776 +
13777 +#define MANAGER_ATTR(_name, _mode, _show, _store) \
13778 + struct manager_attribute manager_attr_##_name = \
13779 + __ATTR(_name, _mode, _show, _store)
13780 +
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);
13796 +
13797 +
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,
13806 + NULL
13807 +};
13808 +
13809 +static ssize_t manager_attr_show(struct kobject *kobj, struct attribute *attr,
13810 + char *buf)
13811 +{
13812 + struct omap_overlay_manager *manager;
13813 + struct manager_attribute *manager_attr;
13814 +
13815 + manager = container_of(kobj, struct omap_overlay_manager, kobj);
13816 + manager_attr = container_of(attr, struct manager_attribute, attr);
13817 +
13818 + if (!manager_attr->show)
13819 + return -ENOENT;
13820 +
13821 + return manager_attr->show(manager, buf);
13822 +}
13823 +
13824 +static ssize_t manager_attr_store(struct kobject *kobj, struct attribute *attr,
13825 + const char *buf, size_t size)
13826 +{
13827 + struct omap_overlay_manager *manager;
13828 + struct manager_attribute *manager_attr;
13829 +
13830 + manager = container_of(kobj, struct omap_overlay_manager, kobj);
13831 + manager_attr = container_of(attr, struct manager_attribute, attr);
13832 +
13833 + if (!manager_attr->store)
13834 + return -ENOENT;
13835 +
13836 + return manager_attr->store(manager, buf, size);
13837 +}
13838 +
13839 +static struct sysfs_ops manager_sysfs_ops = {
13840 + .show = manager_attr_show,
13841 + .store = manager_attr_store,
13842 +};
13843 +
13844 +static struct kobj_type manager_ktype = {
13845 + .sysfs_ops = &manager_sysfs_ops,
13846 + .default_attrs = manager_sysfs_attrs,
13847 +};
13848 +
13849 +/*
13850 + * We have 4 levels of cache for the dispc settings. First two are in SW and
13851 + * the latter two in HW.
13852 + *
13853 + * +--------------------+
13854 + * |overlay/manager_info|
13855 + * +--------------------+
13856 + * v
13857 + * apply()
13858 + * v
13859 + * +--------------------+
13860 + * | dss_cache |
13861 + * +--------------------+
13862 + * v
13863 + * configure()
13864 + * v
13865 + * +--------------------+
13866 + * | shadow registers |
13867 + * +--------------------+
13868 + * v
13869 + * VFP or lcd/digit_enable
13870 + * v
13871 + * +--------------------+
13872 + * | registers |
13873 + * +--------------------+
13874 + */
13875 +
13876 +struct overlay_cache_data {
13877 + /* If true, cache changed, but not written to shadow registers. Set
13878 + * in apply(), cleared when registers written. */
13879 + bool dirty;
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;
13884 +
13885 + bool enabled;
13886 +
13887 + u32 paddr;
13888 + void __iomem *vaddr;
13889 + u16 screen_width;
13890 + u16 width;
13891 + u16 height;
13892 + enum omap_color_mode color_mode;
13893 + u8 rotation;
13894 + enum omap_dss_rotation_type rotation_type;
13895 + bool mirror;
13896 +
13897 + u16 pos_x;
13898 + u16 pos_y;
13899 + u16 out_width; /* if 0, out_width == width */
13900 + u16 out_height; /* if 0, out_height == height */
13901 + u8 global_alpha;
13902 +
13903 + enum omap_channel channel;
13904 + bool replication;
13905 + bool ilace;
13906 +
13907 + enum omap_burst_size burst_size;
13908 + u32 fifo_low;
13909 + u32 fifo_high;
13910 +
13911 + bool manual_update;
13912 +};
13913 +
13914 +struct manager_cache_data {
13915 + /* If true, cache changed, but not written to shadow registers. Set
13916 + * in apply(), cleared when registers written. */
13917 + bool dirty;
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;
13922 +
13923 + u32 default_color;
13924 +
13925 + enum omap_dss_trans_key_type trans_key_type;
13926 + u32 trans_key;
13927 + bool trans_enabled;
13928 +
13929 + bool alpha_enabled;
13930 +
13931 + bool manual_upd_display;
13932 + bool manual_update;
13933 + bool do_manual_update;
13934 +
13935 + /* manual update region */
13936 + u16 x, y, w, h;
13937 +};
13938 +
13939 +static struct {
13940 + spinlock_t lock;
13941 + struct overlay_cache_data overlay_cache[3];
13942 + struct manager_cache_data manager_cache[2];
13943 +
13944 + bool irq_enabled;
13945 +} dss_cache;
13946 +
13947 +
13948 +
13949 +static int omap_dss_set_device(struct omap_overlay_manager *mgr,
13950 + struct omap_dss_device *dssdev)
13951 +{
13952 + int i;
13953 + int r;
13954 +
13955 + if (dssdev->manager) {
13956 + DSSERR("display '%s' already has a manager '%s'\n",
13957 + dssdev->name, dssdev->manager->name);
13958 + return -EINVAL;
13959 + }
13960 +
13961 + if ((mgr->supported_displays & dssdev->type) == 0) {
13962 + DSSERR("display '%s' does not support manager '%s'\n",
13963 + dssdev->name, mgr->name);
13964 + return -EINVAL;
13965 + }
13966 +
13967 + for (i = 0; i < mgr->num_overlays; i++) {
13968 + struct omap_overlay *ovl = mgr->overlays[i];
13969 +
13970 + if (ovl->manager != mgr || !ovl->info.enabled)
13971 + continue;
13972 +
13973 + r = dss_check_overlay(ovl, dssdev);
13974 + if (r)
13975 + return r;
13976 + }
13977 +
13978 + dssdev->manager = mgr;
13979 + mgr->device = dssdev;
13980 + mgr->device_changed = true;
13981 +
13982 + return 0;
13983 +}
13984 +
13985 +static int omap_dss_unset_device(struct omap_overlay_manager *mgr)
13986 +{
13987 + if (!mgr->device) {
13988 + DSSERR("failed to unset display, display not set.\n");
13989 + return -EINVAL;
13990 + }
13991 +
13992 + mgr->device->manager = NULL;
13993 + mgr->device = NULL;
13994 + mgr->device_changed = true;
13995 +
13996 + return 0;
13997 +}
13998 +
13999 +static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
14000 +{
14001 + unsigned long timeout = msecs_to_jiffies(500);
14002 + struct manager_cache_data *mc;
14003 + enum omap_channel channel;
14004 + u32 irq;
14005 + int r;
14006 + int i;
14007 +
14008 + if (!mgr->device)
14009 + return 0;
14010 +
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;
14014 + } else {
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)
14019 + return 0;
14020 +
14021 + irq = DISPC_IRQ_FRAMEDONE;
14022 + } else {
14023 + irq = DISPC_IRQ_VSYNC;
14024 + }
14025 + channel = OMAP_DSS_CHANNEL_LCD;
14026 + }
14027 +
14028 + mc = &dss_cache.manager_cache[mgr->id];
14029 + i = 0;
14030 + while (1) {
14031 + unsigned long flags;
14032 + bool shadow_dirty, dirty;
14033 +
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);
14038 +
14039 + if (!dirty && !shadow_dirty) {
14040 + r = 0;
14041 + break;
14042 + }
14043 +
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 */
14049 + if (i++ == 3) {
14050 + DSSERR("mgr(%d)->wait_for_go() not finishing\n",
14051 + mgr->id);
14052 + r = 0;
14053 + break;
14054 + }
14055 +
14056 + r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
14057 + if (r == -ERESTARTSYS)
14058 + break;
14059 +
14060 + if (r) {
14061 + DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id);
14062 + break;
14063 + }
14064 + }
14065 +
14066 + return r;
14067 +}
14068 +
14069 +int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
14070 +{
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;
14075 + u32 irq;
14076 + int r;
14077 + int i;
14078 +
14079 + if (!ovl->manager || !ovl->manager->device)
14080 + return 0;
14081 +
14082 + dssdev = ovl->manager->device;
14083 +
14084 + if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) {
14085 + irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
14086 + channel = OMAP_DSS_CHANNEL_DIGIT;
14087 + } else {
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)
14092 + return 0;
14093 +
14094 + irq = DISPC_IRQ_FRAMEDONE;
14095 + } else {
14096 + irq = DISPC_IRQ_VSYNC;
14097 + }
14098 + channel = OMAP_DSS_CHANNEL_LCD;
14099 + }
14100 +
14101 + oc = &dss_cache.overlay_cache[ovl->id];
14102 + i = 0;
14103 + while (1) {
14104 + unsigned long flags;
14105 + bool shadow_dirty, dirty;
14106 +
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);
14111 +
14112 + if (!dirty && !shadow_dirty) {
14113 + r = 0;
14114 + break;
14115 + }
14116 +
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 */
14122 + if (i++ == 3) {
14123 + DSSERR("ovl(%d)->wait_for_go() not finishing\n",
14124 + ovl->id);
14125 + r = 0;
14126 + break;
14127 + }
14128 +
14129 + r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
14130 + if (r == -ERESTARTSYS)
14131 + break;
14132 +
14133 + if (r) {
14134 + DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id);
14135 + break;
14136 + }
14137 + }
14138 +
14139 + return r;
14140 +}
14141 +
14142 +static int overlay_enabled(struct omap_overlay *ovl)
14143 +{
14144 + return ovl->info.enabled && ovl->manager && ovl->manager->device;
14145 +}
14146 +
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)
14150 +{
14151 + if (x1 < x2 || y1 < y2)
14152 + return false;
14153 +
14154 + if (x1 + w1 > x2 + w2)
14155 + return false;
14156 +
14157 + if (y1 + h1 > y2 + h2)
14158 + return false;
14159 +
14160 + return true;
14161 +}
14162 +
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)
14166 +{
14167 + if (x1 >= x2 + w2)
14168 + return false;
14169 +
14170 + if (x2 >= x1 + w1)
14171 + return false;
14172 +
14173 + if (y1 >= y2 + h2)
14174 + return false;
14175 +
14176 + if (y2 >= y1 + h1)
14177 + return false;
14178 +
14179 + return true;
14180 +}
14181 +
14182 +static bool dispc_is_overlay_scaled(struct overlay_cache_data *oc)
14183 +{
14184 + if (oc->out_width != 0 && oc->width != oc->out_width)
14185 + return true;
14186 +
14187 + if (oc->out_height != 0 && oc->height != oc->out_height)
14188 + return true;
14189 +
14190 + return false;
14191 +}
14192 +
14193 +static int configure_overlay(enum omap_plane plane)
14194 +{
14195 + struct overlay_cache_data *c;
14196 + struct manager_cache_data *mc;
14197 + u16 outw, outh;
14198 + u16 x, y, w, h;
14199 + u32 paddr;
14200 + int r;
14201 +
14202 + DSSDBGF("%d", plane);
14203 +
14204 + c = &dss_cache.overlay_cache[plane];
14205 +
14206 + if (!c->enabled) {
14207 + dispc_enable_plane(plane, 0);
14208 + return 0;
14209 + }
14210 +
14211 + mc = &dss_cache.manager_cache[c->channel];
14212 +
14213 + x = c->pos_x;
14214 + y = c->pos_y;
14215 + w = c->width;
14216 + h = c->height;
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;
14220 +
14221 + if (c->manual_update && mc->do_manual_update) {
14222 + unsigned bpp;
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);
14227 + return 0;
14228 + }
14229 +
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:
14235 + bpp = 16;
14236 + break;
14237 +
14238 + case OMAP_DSS_COLOR_RGB24P:
14239 + bpp = 24;
14240 + break;
14241 +
14242 + case OMAP_DSS_COLOR_RGB24U:
14243 + case OMAP_DSS_COLOR_ARGB32:
14244 + case OMAP_DSS_COLOR_RGBA32:
14245 + case OMAP_DSS_COLOR_RGBX32:
14246 + bpp = 32;
14247 + break;
14248 +
14249 + default:
14250 + BUG();
14251 + }
14252 +
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;
14259 + } else {
14260 + if (mc->x > c->pos_x) {
14261 + x = 0;
14262 + w -= (mc->x - c->pos_x);
14263 + paddr += (mc->x - c->pos_x) * bpp / 8;
14264 + } else {
14265 + x = c->pos_x - mc->x;
14266 + }
14267 +
14268 + if (mc->y > c->pos_y) {
14269 + y = 0;
14270 + h -= (mc->y - c->pos_y);
14271 + paddr += (mc->y - c->pos_y) * c->screen_width *
14272 + bpp / 8;
14273 + } else {
14274 + y = c->pos_y - mc->y;
14275 + }
14276 +
14277 + if (mc->w < (x+w))
14278 + w -= (x+w) - (mc->w);
14279 +
14280 + if (mc->h < (y+h))
14281 + h -= (y+h) - (mc->h);
14282 +
14283 + outw = w;
14284 + outh = h;
14285 + }
14286 + }
14287 +
14288 + r = dispc_setup_plane(plane,
14289 + paddr,
14290 + c->screen_width,
14291 + x, y,
14292 + w, h,
14293 + outw, outh,
14294 + c->color_mode,
14295 + c->ilace,
14296 + c->rotation_type,
14297 + c->rotation,
14298 + c->mirror,
14299 + c->global_alpha);
14300 +
14301 + if (r) {
14302 + /* this shouldn't happen */
14303 + DSSERR("dispc_setup_plane failed for ovl %d\n", plane);
14304 + dispc_enable_plane(plane, 0);
14305 + return r;
14306 + }
14307 +
14308 + dispc_enable_replication(plane, c->replication);
14309 +
14310 + dispc_set_burst_size(plane, c->burst_size);
14311 + dispc_setup_plane_fifo(plane, c->fifo_low, c->fifo_high);
14312 +
14313 + dispc_enable_plane(plane, 1);
14314 +
14315 + return 0;
14316 +}
14317 +
14318 +static void configure_manager(enum omap_channel channel)
14319 +{
14320 + struct manager_cache_data *c;
14321 +
14322 + DSSDBGF("%d", channel);
14323 +
14324 + c = &dss_cache.manager_cache[channel];
14325 +
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);
14329 +}
14330 +
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)
14336 +{
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);
14341 + int i;
14342 + int r;
14343 + bool mgr_busy[2];
14344 + bool mgr_go[2];
14345 + bool busy;
14346 +
14347 + r = 0;
14348 + busy = false;
14349 +
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;
14354 +
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];
14359 +
14360 + if (!oc->dirty)
14361 + continue;
14362 +
14363 + if (oc->manual_update && !mc->do_manual_update)
14364 + continue;
14365 +
14366 + if (mgr_busy[oc->channel]) {
14367 + busy = true;
14368 + continue;
14369 + }
14370 +
14371 + r = configure_overlay(i);
14372 + if (r)
14373 + DSSERR("configure_overlay %d failed\n", i);
14374 +
14375 + oc->dirty = false;
14376 + oc->shadow_dirty = true;
14377 + mgr_go[oc->channel] = true;
14378 + }
14379 +
14380 + /* Commit manager settings */
14381 + for (i = 0; i < num_mgrs; ++i) {
14382 + mc = &dss_cache.manager_cache[i];
14383 +
14384 + if (!mc->dirty)
14385 + continue;
14386 +
14387 + if (mc->manual_update && !mc->do_manual_update)
14388 + continue;
14389 +
14390 + if (mgr_busy[i]) {
14391 + busy = true;
14392 + continue;
14393 + }
14394 +
14395 + configure_manager(i);
14396 + mc->dirty = false;
14397 + mc->shadow_dirty = true;
14398 + mgr_go[i] = true;
14399 + }
14400 +
14401 + /* set GO */
14402 + for (i = 0; i < num_mgrs; ++i) {
14403 + mc = &dss_cache.manager_cache[i];
14404 +
14405 + if (!mgr_go[i])
14406 + continue;
14407 +
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)
14412 + dispc_go(i);
14413 + }
14414 +
14415 + if (busy)
14416 + r = 1;
14417 + else
14418 + r = 0;
14419 +
14420 + return r;
14421 +}
14422 +
14423 +/* Configure dispc for partial update. Return possibly modified update
14424 + * area */
14425 +void dss_setup_partial_planes(struct omap_dss_device *dssdev,
14426 + u16 *xi, u16 *yi, u16 *wi, u16 *hi)
14427 +{
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;
14432 + int i;
14433 + u16 x, y, w, h;
14434 + unsigned long flags;
14435 +
14436 + x = *xi;
14437 + y = *yi;
14438 + w = *wi;
14439 + h = *hi;
14440 +
14441 + DSSDBG("dispc_setup_partial_planes %d,%d %dx%d\n",
14442 + *xi, *yi, *wi, *hi);
14443 +
14444 + mgr = dssdev->manager;
14445 +
14446 + if (!mgr) {
14447 + DSSDBG("no manager\n");
14448 + return;
14449 + }
14450 +
14451 + spin_lock_irqsave(&dss_cache.lock, flags);
14452 +
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;
14459 +
14460 + oc = &dss_cache.overlay_cache[i];
14461 +
14462 + if (oc->channel != mgr->id)
14463 + continue;
14464 +
14465 + oc->dirty = true;
14466 +
14467 + if (!oc->enabled)
14468 + continue;
14469 +
14470 + if (!dispc_is_overlay_scaled(oc))
14471 + continue;
14472 +
14473 + outw = oc->out_width == 0 ? oc->width : oc->out_width;
14474 + outh = oc->out_height == 0 ? oc->height : oc->out_height;
14475 +
14476 + /* is the overlay outside the update region? */
14477 + if (!rectangle_intersects(x, y, w, h,
14478 + oc->pos_x, oc->pos_y,
14479 + outw, outh))
14480 + continue;
14481 +
14482 + /* if the overlay totally inside the update region? */
14483 + if (rectangle_subset(oc->pos_x, oc->pos_y, outw, outh,
14484 + x, y, w, h))
14485 + continue;
14486 +
14487 + if (x > oc->pos_x)
14488 + x1 = oc->pos_x;
14489 + else
14490 + x1 = x;
14491 +
14492 + if (y > oc->pos_y)
14493 + y1 = oc->pos_y;
14494 + else
14495 + y1 = y;
14496 +
14497 + if ((x + w) < (oc->pos_x + outw))
14498 + x2 = oc->pos_x + outw;
14499 + else
14500 + x2 = x + w;
14501 +
14502 + if ((y + h) < (oc->pos_y + outh))
14503 + y2 = oc->pos_y + outh;
14504 + else
14505 + y2 = y + h;
14506 +
14507 + x = x1;
14508 + y = y1;
14509 + w = x2 - x1;
14510 + h = y2 - y1;
14511 +
14512 + DSSDBG("changing upd area due to ovl(%d) scaling %d,%d %dx%d\n",
14513 + i, x, y, w, h);
14514 + }
14515 +
14516 + mc = &dss_cache.manager_cache[mgr->id];
14517 + mc->do_manual_update = true;
14518 + mc->x = x;
14519 + mc->y = y;
14520 + mc->w = w;
14521 + mc->h = h;
14522 +
14523 + configure_dispc();
14524 +
14525 + mc->do_manual_update = false;
14526 +
14527 + spin_unlock_irqrestore(&dss_cache.lock, flags);
14528 +
14529 + *xi = x;
14530 + *yi = y;
14531 + *wi = w;
14532 + *hi = h;
14533 +}
14534 +
14535 +void dss_start_update(struct omap_dss_device *dssdev)
14536 +{
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;
14542 + int i;
14543 +
14544 + mgr = dssdev->manager;
14545 +
14546 + for (i = 0; i < num_ovls; ++i) {
14547 + oc = &dss_cache.overlay_cache[i];
14548 + if (oc->channel != mgr->id)
14549 + continue;
14550 +
14551 + oc->shadow_dirty = false;
14552 + }
14553 +
14554 + for (i = 0; i < num_mgrs; ++i) {
14555 + mc = &dss_cache.manager_cache[i];
14556 + if (mgr->id != i)
14557 + continue;
14558 +
14559 + mc->shadow_dirty = false;
14560 + }
14561 +
14562 + dispc_enable_lcd_out(1);
14563 +}
14564 +
14565 +static void dss_apply_irq_handler(void *data, u32 mask)
14566 +{
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);
14571 + int i, r;
14572 + bool mgr_busy[2];
14573 +
14574 + mgr_busy[0] = dispc_go_busy(0);
14575 + mgr_busy[1] = dispc_go_busy(1);
14576 +
14577 + spin_lock(&dss_cache.lock);
14578 +
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;
14583 + }
14584 +
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;
14589 + }
14590 +
14591 + r = configure_dispc();
14592 + if (r == 1)
14593 + goto end;
14594 +
14595 + /* re-read busy flags */
14596 + mgr_busy[0] = dispc_go_busy(0);
14597 + mgr_busy[1] = dispc_go_busy(1);
14598 +
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) {
14602 + if (mgr_busy[i])
14603 + goto end;
14604 + }
14605 +
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;
14610 +
14611 +end:
14612 + spin_unlock(&dss_cache.lock);
14613 +}
14614 +
14615 +static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
14616 +{
14617 + struct overlay_cache_data *oc;
14618 + struct manager_cache_data *mc;
14619 + int i;
14620 + struct omap_overlay *ovl;
14621 + int num_planes_enabled = 0;
14622 + bool use_fifomerge;
14623 + unsigned long flags;
14624 + int r;
14625 +
14626 + DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
14627 +
14628 + spin_lock_irqsave(&dss_cache.lock, flags);
14629 +
14630 + /* Configure overlays */
14631 + for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
14632 + struct omap_dss_device *dssdev;
14633 +
14634 + ovl = omap_dss_get_overlay(i);
14635 +
14636 + if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
14637 + continue;
14638 +
14639 + oc = &dss_cache.overlay_cache[ovl->id];
14640 +
14641 + if (!overlay_enabled(ovl)) {
14642 + if (oc->enabled) {
14643 + oc->enabled = false;
14644 + oc->dirty = true;
14645 + }
14646 + continue;
14647 + }
14648 +
14649 + if (!ovl->info_dirty) {
14650 + if (oc->enabled)
14651 + ++num_planes_enabled;
14652 + continue;
14653 + }
14654 +
14655 + dssdev = ovl->manager->device;
14656 +
14657 + if (dss_check_overlay(ovl, dssdev)) {
14658 + if (oc->enabled) {
14659 + oc->enabled = false;
14660 + oc->dirty = true;
14661 + }
14662 + continue;
14663 + }
14664 +
14665 + ovl->info_dirty = false;
14666 + oc->dirty = true;
14667 +
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;
14682 +
14683 + oc->replication =
14684 + dss_use_replication(dssdev, ovl->info.color_mode);
14685 +
14686 + oc->ilace = dssdev->type == OMAP_DISPLAY_TYPE_VENC;
14687 +
14688 + oc->channel = ovl->manager->id;
14689 +
14690 + oc->enabled = true;
14691 +
14692 + oc->manual_update =
14693 + dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE &&
14694 + dssdev->get_update_mode(dssdev) != OMAP_DSS_UPDATE_AUTO;
14695 +
14696 + ++num_planes_enabled;
14697 + }
14698 +
14699 + /* Configure managers */
14700 + list_for_each_entry(mgr, &manager_list, list) {
14701 + struct omap_dss_device *dssdev;
14702 +
14703 + if (!(mgr->caps & OMAP_DSS_OVL_MGR_CAP_DISPC))
14704 + continue;
14705 +
14706 + mc = &dss_cache.manager_cache[mgr->id];
14707 +
14708 + if (mgr->device_changed) {
14709 + mgr->device_changed = false;
14710 + mgr->info_dirty = true;
14711 + }
14712 +
14713 + if (!mgr->info_dirty)
14714 + continue;
14715 +
14716 + if (!mgr->device)
14717 + continue;
14718 +
14719 + dssdev = mgr->device;
14720 +
14721 + mgr->info_dirty = false;
14722 + mc->dirty = true;
14723 +
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;
14729 +
14730 + mc->manual_upd_display =
14731 + dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
14732 +
14733 + mc->manual_update =
14734 + dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE &&
14735 + dssdev->get_update_mode(dssdev) != OMAP_DSS_UPDATE_AUTO;
14736 + }
14737 +
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
14750 + */
14751 + use_fifomerge = false;
14752 +
14753 + /* Configure overlay fifos */
14754 + for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
14755 + struct omap_dss_device *dssdev;
14756 + u32 size;
14757 +
14758 + ovl = omap_dss_get_overlay(i);
14759 +
14760 + if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
14761 + continue;
14762 +
14763 + oc = &dss_cache.overlay_cache[ovl->id];
14764 +
14765 + if (!oc->enabled)
14766 + continue;
14767 +
14768 + dssdev = ovl->manager->device;
14769 +
14770 + size = dispc_get_plane_fifo_size(ovl->id);
14771 + if (use_fifomerge)
14772 + size *= 3;
14773 +
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,
14781 + &oc->fifo_high);
14782 + break;
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,
14787 + &oc->fifo_high);
14788 + break;
14789 +#endif
14790 + default:
14791 + BUG();
14792 + }
14793 + }
14794 +
14795 + r = 0;
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;
14802 + }
14803 + configure_dispc();
14804 + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
14805 +
14806 + spin_unlock_irqrestore(&dss_cache.lock, flags);
14807 +
14808 + return r;
14809 +}
14810 +
14811 +static int dss_check_manager(struct omap_overlay_manager *mgr)
14812 +{
14813 + /* OMAP supports only graphics source transparency color key and alpha
14814 + * blending simultaneously. See TRM 15.4.2.4.2.2 Alpha Mode */
14815 +
14816 + if (mgr->info.alpha_enabled && mgr->info.trans_enabled &&
14817 + mgr->info.trans_key_type != OMAP_DSS_COLOR_KEY_GFX_DST)
14818 + return -EINVAL;
14819 +
14820 + return 0;
14821 +}
14822 +
14823 +static int omap_dss_mgr_set_info(struct omap_overlay_manager *mgr,
14824 + struct omap_overlay_manager_info *info)
14825 +{
14826 + int r;
14827 + struct omap_overlay_manager_info old_info;
14828 +
14829 + old_info = mgr->info;
14830 + mgr->info = *info;
14831 +
14832 + r = dss_check_manager(mgr);
14833 + if (r) {
14834 + mgr->info = old_info;
14835 + return r;
14836 + }
14837 +
14838 + mgr->info_dirty = true;
14839 +
14840 + return 0;
14841 +}
14842 +
14843 +static void omap_dss_mgr_get_info(struct omap_overlay_manager *mgr,
14844 + struct omap_overlay_manager_info *info)
14845 +{
14846 + *info = mgr->info;
14847 +}
14848 +
14849 +static void omap_dss_add_overlay_manager(struct omap_overlay_manager *manager)
14850 +{
14851 + ++num_managers;
14852 + list_add_tail(&manager->list, &manager_list);
14853 +}
14854 +
14855 +int dss_init_overlay_managers(struct platform_device *pdev)
14856 +{
14857 + int i, r;
14858 +
14859 + spin_lock_init(&dss_cache.lock);
14860 +
14861 + INIT_LIST_HEAD(&manager_list);
14862 +
14863 + num_managers = 0;
14864 +
14865 + for (i = 0; i < 2; ++i) {
14866 + struct omap_overlay_manager *mgr;
14867 + mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
14868 +
14869 + BUG_ON(mgr == NULL);
14870 +
14871 + switch (i) {
14872 + case 0:
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;
14878 + break;
14879 + case 1:
14880 + mgr->name = "tv";
14881 + mgr->id = OMAP_DSS_CHANNEL_DIGIT;
14882 + mgr->supported_displays = OMAP_DISPLAY_TYPE_VENC;
14883 + break;
14884 + }
14885 +
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;
14892 +
14893 + mgr->caps = OMAP_DSS_OVL_MGR_CAP_DISPC;
14894 +
14895 + dss_overlay_setup_dispc_manager(mgr);
14896 +
14897 + omap_dss_add_overlay_manager(mgr);
14898 +
14899 + r = kobject_init_and_add(&mgr->kobj, &manager_ktype,
14900 + &pdev->dev.kobj, "manager%d", i);
14901 +
14902 + if (r) {
14903 + DSSERR("failed to create sysfs file\n");
14904 + continue;
14905 + }
14906 + }
14907 +
14908 +#ifdef L4_EXAMPLE
14909 + {
14910 + int omap_dss_mgr_apply_l4(struct omap_overlay_manager *mgr)
14911 + {
14912 + DSSDBG("omap_dss_mgr_apply_l4(%s)\n", mgr->name);
14913 +
14914 + return 0;
14915 + }
14916 +
14917 + struct omap_overlay_manager *mgr;
14918 + mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
14919 +
14920 + BUG_ON(mgr == NULL);
14921 +
14922 + mgr->name = "l4";
14923 + mgr->supported_displays =
14924 + OMAP_DISPLAY_TYPE_DBI | OMAP_DISPLAY_TYPE_DSI;
14925 +
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;
14931 +
14932 + dss_overlay_setup_l4_manager(mgr);
14933 +
14934 + omap_dss_add_overlay_manager(mgr);
14935 +
14936 + r = kobject_init_and_add(&mgr->kobj, &manager_ktype,
14937 + &pdev->dev.kobj, "managerl4");
14938 +
14939 + if (r)
14940 + DSSERR("failed to create sysfs file\n");
14941 + }
14942 +#endif
14943 +
14944 + return 0;
14945 +}
14946 +
14947 +void dss_uninit_overlay_managers(struct platform_device *pdev)
14948 +{
14949 + struct omap_overlay_manager *mgr;
14950 +
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);
14957 + kfree(mgr);
14958 + }
14959 +
14960 + num_managers = 0;
14961 +}
14962 +
14963 +int omap_dss_get_num_overlay_managers(void)
14964 +{
14965 + return num_managers;
14966 +}
14967 +EXPORT_SYMBOL(omap_dss_get_num_overlay_managers);
14968 +
14969 +struct omap_overlay_manager *omap_dss_get_overlay_manager(int num)
14970 +{
14971 + int i = 0;
14972 + struct omap_overlay_manager *mgr;
14973 +
14974 + list_for_each_entry(mgr, &manager_list, list) {
14975 + if (i++ == num)
14976 + return mgr;
14977 + }
14978 +
14979 + return NULL;
14980 +}
14981 +EXPORT_SYMBOL(omap_dss_get_overlay_manager);
14982 +
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
14986 --- /dev/null
14987 +++ b/drivers/video/omap2/dss/overlay.c
14988 @@ -0,0 +1,673 @@
14989 +/*
14990 + * linux/drivers/video/omap2/dss/overlay.c
14991 + *
14992 + * Copyright (C) 2009 Nokia Corporation
14993 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
14994 + *
14995 + * Some code and ideas taken from drivers/video/omap/ driver
14996 + * by Imre Deak.
14997 + *
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.
15001 + *
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
15005 + * more details.
15006 + *
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/>.
15009 + */
15010 +
15011 +#define DSS_SUBSYS_NAME "OVERLAY"
15012 +
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>
15020 +
15021 +#include <mach/display.h>
15022 +
15023 +#include "dss.h"
15024 +
15025 +static int num_overlays;
15026 +static struct list_head overlay_list;
15027 +
15028 +static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf)
15029 +{
15030 + return snprintf(buf, PAGE_SIZE, "%s\n", ovl->name);
15031 +}
15032 +
15033 +static ssize_t overlay_manager_show(struct omap_overlay *ovl, char *buf)
15034 +{
15035 + return snprintf(buf, PAGE_SIZE, "%s\n",
15036 + ovl->manager ? ovl->manager->name : "<none>");
15037 +}
15038 +
15039 +static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf,
15040 + size_t size)
15041 +{
15042 + int i, r;
15043 + struct omap_overlay_manager *mgr = NULL;
15044 + struct omap_overlay_manager *old_mgr;
15045 + int len = size;
15046 +
15047 + if (buf[size-1] == '\n')
15048 + --len;
15049 +
15050 + if (len > 0) {
15051 + for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
15052 + mgr = omap_dss_get_overlay_manager(i);
15053 +
15054 + if (strncmp(buf, mgr->name, len) == 0)
15055 + break;
15056 +
15057 + mgr = NULL;
15058 + }
15059 + }
15060 +
15061 + if (len > 0 && mgr == NULL)
15062 + return -EINVAL;
15063 +
15064 + if (mgr)
15065 + DSSDBG("manager %s found\n", mgr->name);
15066 +
15067 + if (mgr == ovl->manager)
15068 + return size;
15069 +
15070 + old_mgr = ovl->manager;
15071 +
15072 + /* detach old manager */
15073 + if (old_mgr) {
15074 + r = ovl->unset_manager(ovl);
15075 + if (r) {
15076 + DSSERR("detach failed\n");
15077 + return r;
15078 + }
15079 +
15080 + r = old_mgr->apply(old_mgr);
15081 + if (r)
15082 + return r;
15083 + }
15084 +
15085 + if (mgr) {
15086 + r = ovl->set_manager(ovl, mgr);
15087 + if (r) {
15088 + DSSERR("Failed to attach overlay\n");
15089 + return r;
15090 + }
15091 +
15092 + r = mgr->apply(mgr);
15093 + if (r)
15094 + return r;
15095 + }
15096 +
15097 + return size;
15098 +}
15099 +
15100 +static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf)
15101 +{
15102 + return snprintf(buf, PAGE_SIZE, "%d,%d\n",
15103 + ovl->info.width, ovl->info.height);
15104 +}
15105 +
15106 +static ssize_t overlay_screen_width_show(struct omap_overlay *ovl, char *buf)
15107 +{
15108 + return snprintf(buf, PAGE_SIZE, "%d\n", ovl->info.screen_width);
15109 +}
15110 +
15111 +static ssize_t overlay_position_show(struct omap_overlay *ovl, char *buf)
15112 +{
15113 + return snprintf(buf, PAGE_SIZE, "%d,%d\n",
15114 + ovl->info.pos_x, ovl->info.pos_y);
15115 +}
15116 +
15117 +static ssize_t overlay_position_store(struct omap_overlay *ovl,
15118 + const char *buf, size_t size)
15119 +{
15120 + int r;
15121 + char *last;
15122 + struct omap_overlay_info info;
15123 +
15124 + ovl->get_overlay_info(ovl, &info);
15125 +
15126 + info.pos_x = simple_strtoul(buf, &last, 10);
15127 + ++last;
15128 + if (last - buf >= size)
15129 + return -EINVAL;
15130 +
15131 + info.pos_y = simple_strtoul(last, &last, 10);
15132 +
15133 + r = ovl->set_overlay_info(ovl, &info);
15134 + if (r)
15135 + return r;
15136 +
15137 + if (ovl->manager) {
15138 + r = ovl->manager->apply(ovl->manager);
15139 + if (r)
15140 + return r;
15141 + }
15142 +
15143 + return size;
15144 +}
15145 +
15146 +static ssize_t overlay_output_size_show(struct omap_overlay *ovl, char *buf)
15147 +{
15148 + return snprintf(buf, PAGE_SIZE, "%d,%d\n",
15149 + ovl->info.out_width, ovl->info.out_height);
15150 +}
15151 +
15152 +static ssize_t overlay_output_size_store(struct omap_overlay *ovl,
15153 + const char *buf, size_t size)
15154 +{
15155 + int r;
15156 + char *last;
15157 + struct omap_overlay_info info;
15158 +
15159 + ovl->get_overlay_info(ovl, &info);
15160 +
15161 + info.out_width = simple_strtoul(buf, &last, 10);
15162 + ++last;
15163 + if (last - buf >= size)
15164 + return -EINVAL;
15165 +
15166 + info.out_height = simple_strtoul(last, &last, 10);
15167 +
15168 + r = ovl->set_overlay_info(ovl, &info);
15169 + if (r)
15170 + return r;
15171 +
15172 + if (ovl->manager) {
15173 + r = ovl->manager->apply(ovl->manager);
15174 + if (r)
15175 + return r;
15176 + }
15177 +
15178 + return size;
15179 +}
15180 +
15181 +static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf)
15182 +{
15183 + return snprintf(buf, PAGE_SIZE, "%d\n", ovl->info.enabled);
15184 +}
15185 +
15186 +static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf,
15187 + size_t size)
15188 +{
15189 + int r;
15190 + struct omap_overlay_info info;
15191 +
15192 + ovl->get_overlay_info(ovl, &info);
15193 +
15194 + info.enabled = simple_strtoul(buf, NULL, 10);
15195 +
15196 + r = ovl->set_overlay_info(ovl, &info);
15197 + if (r)
15198 + return r;
15199 +
15200 + if (ovl->manager) {
15201 + r = ovl->manager->apply(ovl->manager);
15202 + if (r)
15203 + return r;
15204 + }
15205 +
15206 + return size;
15207 +}
15208 +
15209 +static ssize_t overlay_global_alpha_show(struct omap_overlay *ovl, char *buf)
15210 +{
15211 + return snprintf(buf, PAGE_SIZE, "%d\n",
15212 + ovl->info.global_alpha);
15213 +}
15214 +
15215 +static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl,
15216 + const char *buf, size_t size)
15217 +{
15218 + int r;
15219 + struct omap_overlay_info info;
15220 +
15221 + ovl->get_overlay_info(ovl, &info);
15222 +
15223 + /* Video1 plane does not support global alpha
15224 + * to always make it 255 completely opaque
15225 + */
15226 + if (ovl->id == OMAP_DSS_VIDEO1)
15227 + info.global_alpha = 255;
15228 + else
15229 + info.global_alpha = simple_strtoul(buf, NULL, 10);
15230 +
15231 + r = ovl->set_overlay_info(ovl, &info);
15232 + if (r)
15233 + return r;
15234 +
15235 + if (ovl->manager) {
15236 + r = ovl->manager->apply(ovl->manager);
15237 + if (r)
15238 + return r;
15239 + }
15240 +
15241 + return size;
15242 +}
15243 +
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);
15248 +};
15249 +
15250 +#define OVERLAY_ATTR(_name, _mode, _show, _store) \
15251 + struct overlay_attribute overlay_attr_##_name = \
15252 + __ATTR(_name, _mode, _show, _store)
15253 +
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);
15267 +
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,
15277 + NULL
15278 +};
15279 +
15280 +static ssize_t overlay_attr_show(struct kobject *kobj, struct attribute *attr,
15281 + char *buf)
15282 +{
15283 + struct omap_overlay *overlay;
15284 + struct overlay_attribute *overlay_attr;
15285 +
15286 + overlay = container_of(kobj, struct omap_overlay, kobj);
15287 + overlay_attr = container_of(attr, struct overlay_attribute, attr);
15288 +
15289 + if (!overlay_attr->show)
15290 + return -ENOENT;
15291 +
15292 + return overlay_attr->show(overlay, buf);
15293 +}
15294 +
15295 +static ssize_t overlay_attr_store(struct kobject *kobj, struct attribute *attr,
15296 + const char *buf, size_t size)
15297 +{
15298 + struct omap_overlay *overlay;
15299 + struct overlay_attribute *overlay_attr;
15300 +
15301 + overlay = container_of(kobj, struct omap_overlay, kobj);
15302 + overlay_attr = container_of(attr, struct overlay_attribute, attr);
15303 +
15304 + if (!overlay_attr->store)
15305 + return -ENOENT;
15306 +
15307 + return overlay_attr->store(overlay, buf, size);
15308 +}
15309 +
15310 +static struct sysfs_ops overlay_sysfs_ops = {
15311 + .show = overlay_attr_show,
15312 + .store = overlay_attr_store,
15313 +};
15314 +
15315 +static struct kobj_type overlay_ktype = {
15316 + .sysfs_ops = &overlay_sysfs_ops,
15317 + .default_attrs = overlay_sysfs_attrs,
15318 +};
15319 +
15320 +/* Check if overlay parameters are compatible with display */
15321 +int dss_check_overlay(struct omap_overlay *ovl, struct omap_dss_device *dssdev)
15322 +{
15323 + struct omap_overlay_info *info;
15324 + u16 outw, outh;
15325 + u16 dw, dh;
15326 +
15327 + if (!dssdev)
15328 + return 0;
15329 +
15330 + if (!ovl->info.enabled)
15331 + return 0;
15332 +
15333 + info = &ovl->info;
15334 +
15335 + if (info->paddr == 0) {
15336 + DSSDBG("check_overlay failed: paddr 0\n");
15337 + return -EINVAL;
15338 + }
15339 +
15340 + dssdev->get_resolution(dssdev, &dw, &dh);
15341 +
15342 + DSSDBG("check_overlay %d: (%d,%d %dx%d -> %dx%d) disp (%dx%d)\n",
15343 + ovl->id,
15344 + info->pos_x, info->pos_y,
15345 + info->width, info->height,
15346 + info->out_width, info->out_height,
15347 + dw, dh);
15348 +
15349 + if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
15350 + outw = info->width;
15351 + outh = info->height;
15352 + } else {
15353 + if (info->out_width == 0)
15354 + outw = info->width;
15355 + else
15356 + outw = info->out_width;
15357 +
15358 + if (info->out_height == 0)
15359 + outh = info->height;
15360 + else
15361 + outh = info->out_height;
15362 + }
15363 +
15364 + if (dw < info->pos_x + outw) {
15365 + DSSDBG("check_overlay failed 1: %d < %d + %d\n",
15366 + dw, info->pos_x, outw);
15367 + return -EINVAL;
15368 + }
15369 +
15370 + if (dh < info->pos_y + outh) {
15371 + DSSDBG("check_overlay failed 2: %d < %d + %d\n",
15372 + dh, info->pos_y, outh);
15373 + return -EINVAL;
15374 + }
15375 +
15376 + if ((ovl->supported_modes & info->color_mode) == 0) {
15377 + DSSERR("overlay doesn't support mode %d\n", info->color_mode);
15378 + return -EINVAL;
15379 + }
15380 +
15381 + return 0;
15382 +}
15383 +
15384 +static int dss_ovl_set_overlay_info(struct omap_overlay *ovl,
15385 + struct omap_overlay_info *info)
15386 +{
15387 + int r;
15388 + struct omap_overlay_info old_info;
15389 +
15390 + old_info = ovl->info;
15391 + ovl->info = *info;
15392 +
15393 + if (ovl->manager) {
15394 + r = dss_check_overlay(ovl, ovl->manager->device);
15395 + if (r) {
15396 + ovl->info = old_info;
15397 + return r;
15398 + }
15399 + }
15400 +
15401 + ovl->info_dirty = true;
15402 +
15403 + return 0;
15404 +}
15405 +
15406 +static void dss_ovl_get_overlay_info(struct omap_overlay *ovl,
15407 + struct omap_overlay_info *info)
15408 +{
15409 + *info = ovl->info;
15410 +}
15411 +
15412 +static int dss_ovl_wait_for_go(struct omap_overlay *ovl)
15413 +{
15414 + return dss_mgr_wait_for_go_ovl(ovl);
15415 +}
15416 +
15417 +static int omap_dss_set_manager(struct omap_overlay *ovl,
15418 + struct omap_overlay_manager *mgr)
15419 +{
15420 + if (!mgr)
15421 + return -EINVAL;
15422 +
15423 + if (ovl->manager) {
15424 + DSSERR("overlay '%s' already has a manager '%s'\n",
15425 + ovl->name, ovl->manager->name);
15426 + return -EINVAL;
15427 + }
15428 +
15429 + if (ovl->info.enabled) {
15430 + DSSERR("overlay has to be disabled to change the manager\n");
15431 + return -EINVAL;
15432 + }
15433 +
15434 + ovl->manager = mgr;
15435 +
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. */
15443 + msleep(40);
15444 + dispc_set_channel_out(ovl->id, mgr->id);
15445 + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
15446 +
15447 + return 0;
15448 +}
15449 +
15450 +static int omap_dss_unset_manager(struct omap_overlay *ovl)
15451 +{
15452 + int r;
15453 +
15454 + if (!ovl->manager) {
15455 + DSSERR("failed to detach overlay: manager not set\n");
15456 + return -EINVAL;
15457 + }
15458 +
15459 + if (ovl->info.enabled) {
15460 + DSSERR("overlay has to be disabled to unset the manager\n");
15461 + return -EINVAL;
15462 + }
15463 +
15464 + r = ovl->wait_for_go(ovl);
15465 + if (r)
15466 + return r;
15467 +
15468 + ovl->manager = NULL;
15469 +
15470 + return 0;
15471 +}
15472 +
15473 +int omap_dss_get_num_overlays(void)
15474 +{
15475 + return num_overlays;
15476 +}
15477 +EXPORT_SYMBOL(omap_dss_get_num_overlays);
15478 +
15479 +struct omap_overlay *omap_dss_get_overlay(int num)
15480 +{
15481 + int i = 0;
15482 + struct omap_overlay *ovl;
15483 +
15484 + list_for_each_entry(ovl, &overlay_list, list) {
15485 + if (i++ == num)
15486 + return ovl;
15487 + }
15488 +
15489 + return NULL;
15490 +}
15491 +EXPORT_SYMBOL(omap_dss_get_overlay);
15492 +
15493 +static void omap_dss_add_overlay(struct omap_overlay *overlay)
15494 +{
15495 + ++num_overlays;
15496 + list_add_tail(&overlay->list, &overlay_list);
15497 +}
15498 +
15499 +static struct omap_overlay *dispc_overlays[3];
15500 +
15501 +void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr)
15502 +{
15503 + mgr->num_overlays = 3;
15504 + mgr->overlays = dispc_overlays;
15505 +}
15506 +
15507 +#ifdef L4_EXAMPLE
15508 +static struct omap_overlay *l4_overlays[1];
15509 +void dss_overlay_setup_l4_manager(struct omap_overlay_manager *mgr)
15510 +{
15511 + mgr->num_overlays = 1;
15512 + mgr->overlays = l4_overlays;
15513 +}
15514 +#endif
15515 +
15516 +void dss_init_overlays(struct platform_device *pdev)
15517 +{
15518 + int i, r;
15519 +
15520 + INIT_LIST_HEAD(&overlay_list);
15521 +
15522 + num_overlays = 0;
15523 +
15524 + for (i = 0; i < 3; ++i) {
15525 + struct omap_overlay *ovl;
15526 + ovl = kzalloc(sizeof(*ovl), GFP_KERNEL);
15527 +
15528 + BUG_ON(ovl == NULL);
15529 +
15530 + switch (i) {
15531 + case 0:
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;
15537 + break;
15538 + case 1:
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;
15545 + break;
15546 + case 2:
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;
15553 + break;
15554 + }
15555 +
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;
15561 +
15562 + omap_dss_add_overlay(ovl);
15563 +
15564 + r = kobject_init_and_add(&ovl->kobj, &overlay_ktype,
15565 + &pdev->dev.kobj, "overlay%d", i);
15566 +
15567 + if (r) {
15568 + DSSERR("failed to create sysfs file\n");
15569 + continue;
15570 + }
15571 +
15572 + dispc_overlays[i] = ovl;
15573 + }
15574 +
15575 +#ifdef L4_EXAMPLE
15576 + {
15577 + struct omap_overlay *ovl;
15578 + ovl = kzalloc(sizeof(*ovl), GFP_KERNEL);
15579 +
15580 + BUG_ON(ovl == NULL);
15581 +
15582 + ovl->name = "l4";
15583 + ovl->supported_modes = OMAP_DSS_COLOR_RGB24U;
15584 +
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;
15589 +
15590 + omap_dss_add_overlay(ovl);
15591 +
15592 + r = kobject_init_and_add(&ovl->kobj, &overlay_ktype,
15593 + &pdev->dev.kobj, "overlayl4");
15594 +
15595 + if (r)
15596 + DSSERR("failed to create sysfs file\n");
15597 +
15598 + l4_overlays[0] = ovl;
15599 + }
15600 +#endif
15601 +}
15602 +
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)
15606 +{
15607 + int i;
15608 + struct omap_overlay_manager *lcd_mgr;
15609 + struct omap_overlay_manager *tv_mgr;
15610 + struct omap_overlay_manager *mgr = NULL;
15611 +
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);
15614 +
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);
15620 + mgr = lcd_mgr;
15621 + }
15622 + }
15623 +
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);
15629 + mgr = tv_mgr;
15630 + }
15631 + }
15632 +
15633 + if (mgr) {
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);
15641 + }
15642 + }
15643 + }
15644 +}
15645 +
15646 +void dss_uninit_overlays(struct platform_device *pdev)
15647 +{
15648 + struct omap_overlay *ovl;
15649 +
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);
15656 + kfree(ovl);
15657 + }
15658 +
15659 + num_overlays = 0;
15660 +}
15661 +
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
15665 --- /dev/null
15666 +++ b/drivers/video/omap2/dss/rfbi.c
15667 @@ -0,0 +1,1310 @@
15668 +/*
15669 + * linux/drivers/video/omap2/dss/rfbi.c
15670 + *
15671 + * Copyright (C) 2009 Nokia Corporation
15672 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
15673 + *
15674 + * Some code and ideas taken from drivers/video/omap/ driver
15675 + * by Imre Deak.
15676 + *
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.
15680 + *
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
15684 + * more details.
15685 + *
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/>.
15688 + */
15689 +
15690 +#define DSS_SUBSYS_NAME "RFBI"
15691 +
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>
15702 +
15703 +#include <mach/board.h>
15704 +#include <mach/display.h>
15705 +#include "dss.h"
15706 +
15707 +/*#define MEASURE_PERF*/
15708 +
15709 +#define RFBI_BASE 0x48050800
15710 +
15711 +struct rfbi_reg { u16 idx; };
15712 +
15713 +#define RFBI_REG(idx) ((const struct rfbi_reg) { idx })
15714 +
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)
15726 +
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)
15733 +
15734 +#define RFBI_VSYNC_WIDTH RFBI_REG(0x0090)
15735 +#define RFBI_HSYNC_WIDTH RFBI_REG(0x0094)
15736 +
15737 +#define RFBI_CMD_FIFO_LEN_BYTES (16 * sizeof(struct update_param))
15738 +
15739 +#define REG_FLD_MOD(idx, val, start, end) \
15740 + rfbi_write_reg(idx, FLD_MOD(rfbi_read_reg(idx), val, start, end))
15741 +
15742 +/* To work around an RFBI transfer rate limitation */
15743 +#define OMAP_RFBI_RATE_LIMIT 1
15744 +
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,
15750 +};
15751 +
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,
15757 +};
15758 +
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,
15764 +};
15765 +
15766 +enum update_cmd {
15767 + RFBI_CMD_UPDATE = 0,
15768 + RFBI_CMD_SYNC = 1,
15769 +};
15770 +
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);
15774 +
15775 +static struct {
15776 + void __iomem *base;
15777 +
15778 + unsigned long l4_khz;
15779 +
15780 + enum omap_rfbi_datatype datatype;
15781 + enum omap_rfbi_parallelmode parallelmode;
15782 +
15783 + enum omap_rfbi_te_mode te_mode;
15784 + int te_enabled;
15785 +
15786 + void (*framedone_callback)(void *data);
15787 + void *framedone_callback_data;
15788 +
15789 + struct omap_dss_device *dssdev[2];
15790 +
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;
15800 +#endif
15801 +} rfbi;
15802 +
15803 +struct update_region {
15804 + u16 x;
15805 + u16 y;
15806 + u16 w;
15807 + u16 h;
15808 +};
15809 +
15810 +struct update_param {
15811 + u8 rfbi_module;
15812 + u8 cmd;
15813 +
15814 + union {
15815 + struct update_region r;
15816 + struct completion *sync;
15817 + } par;
15818 +};
15819 +
15820 +static inline void rfbi_write_reg(const struct rfbi_reg idx, u32 val)
15821 +{
15822 + __raw_writel(val, rfbi.base + idx.idx);
15823 +}
15824 +
15825 +static inline u32 rfbi_read_reg(const struct rfbi_reg idx)
15826 +{
15827 + return __raw_readl(rfbi.base + idx.idx);
15828 +}
15829 +
15830 +static void rfbi_enable_clocks(bool enable)
15831 +{
15832 + if (enable)
15833 + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
15834 + else
15835 + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
15836 +}
15837 +
15838 +void omap_rfbi_write_command(const void *buf, u32 len)
15839 +{
15840 + rfbi_enable_clocks(1);
15841 + switch (rfbi.parallelmode) {
15842 + case OMAP_DSS_RFBI_PARALLELMODE_8:
15843 + {
15844 + const u8 *b = buf;
15845 + for (; len; len--)
15846 + rfbi_write_reg(RFBI_CMD, *b++);
15847 + break;
15848 + }
15849 +
15850 + case OMAP_DSS_RFBI_PARALLELMODE_16:
15851 + {
15852 + const u16 *w = buf;
15853 + BUG_ON(len & 1);
15854 + for (; len; len -= 2)
15855 + rfbi_write_reg(RFBI_CMD, *w++);
15856 + break;
15857 + }
15858 +
15859 + case OMAP_DSS_RFBI_PARALLELMODE_9:
15860 + case OMAP_DSS_RFBI_PARALLELMODE_12:
15861 + default:
15862 + BUG();
15863 + }
15864 + rfbi_enable_clocks(0);
15865 +}
15866 +EXPORT_SYMBOL(omap_rfbi_write_command);
15867 +
15868 +void omap_rfbi_read_data(void *buf, u32 len)
15869 +{
15870 + rfbi_enable_clocks(1);
15871 + switch (rfbi.parallelmode) {
15872 + case OMAP_DSS_RFBI_PARALLELMODE_8:
15873 + {
15874 + u8 *b = buf;
15875 + for (; len; len--) {
15876 + rfbi_write_reg(RFBI_READ, 0);
15877 + *b++ = rfbi_read_reg(RFBI_READ);
15878 + }
15879 + break;
15880 + }
15881 +
15882 + case OMAP_DSS_RFBI_PARALLELMODE_16:
15883 + {
15884 + u16 *w = buf;
15885 + BUG_ON(len & ~1);
15886 + for (; len; len -= 2) {
15887 + rfbi_write_reg(RFBI_READ, 0);
15888 + *w++ = rfbi_read_reg(RFBI_READ);
15889 + }
15890 + break;
15891 + }
15892 +
15893 + case OMAP_DSS_RFBI_PARALLELMODE_9:
15894 + case OMAP_DSS_RFBI_PARALLELMODE_12:
15895 + default:
15896 + BUG();
15897 + }
15898 + rfbi_enable_clocks(0);
15899 +}
15900 +EXPORT_SYMBOL(omap_rfbi_read_data);
15901 +
15902 +void omap_rfbi_write_data(const void *buf, u32 len)
15903 +{
15904 + rfbi_enable_clocks(1);
15905 + switch (rfbi.parallelmode) {
15906 + case OMAP_DSS_RFBI_PARALLELMODE_8:
15907 + {
15908 + const u8 *b = buf;
15909 + for (; len; len--)
15910 + rfbi_write_reg(RFBI_PARAM, *b++);
15911 + break;
15912 + }
15913 +
15914 + case OMAP_DSS_RFBI_PARALLELMODE_16:
15915 + {
15916 + const u16 *w = buf;
15917 + BUG_ON(len & 1);
15918 + for (; len; len -= 2)
15919 + rfbi_write_reg(RFBI_PARAM, *w++);
15920 + break;
15921 + }
15922 +
15923 + case OMAP_DSS_RFBI_PARALLELMODE_9:
15924 + case OMAP_DSS_RFBI_PARALLELMODE_12:
15925 + default:
15926 + BUG();
15927 +
15928 + }
15929 + rfbi_enable_clocks(0);
15930 +}
15931 +EXPORT_SYMBOL(omap_rfbi_write_data);
15932 +
15933 +void omap_rfbi_write_pixels(const void __iomem *buf, int scr_width,
15934 + u16 x, u16 y,
15935 + u16 w, u16 h)
15936 +{
15937 + int start_offset = scr_width * y + x;
15938 + int horiz_offset = scr_width - w;
15939 + int i;
15940 +
15941 + rfbi_enable_clocks(1);
15942 +
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;
15947 +
15948 + for (; h; --h) {
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));
15953 + ++pd;
15954 + }
15955 + pd += horiz_offset;
15956 + }
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;
15961 +
15962 + for (; h; --h) {
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));
15968 + ++pd;
15969 + }
15970 + pd += horiz_offset;
15971 + }
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;
15976 +
15977 + for (; h; --h) {
15978 + for (i = 0; i < w; ++i) {
15979 + rfbi_write_reg(RFBI_PARAM, __raw_readw(pd));
15980 + ++pd;
15981 + }
15982 + pd += horiz_offset;
15983 + }
15984 + } else {
15985 + BUG();
15986 + }
15987 +
15988 + rfbi_enable_clocks(0);
15989 +}
15990 +EXPORT_SYMBOL(omap_rfbi_write_pixels);
15991 +
15992 +#ifdef MEASURE_PERF
15993 +static void perf_mark_setup(void)
15994 +{
15995 + rfbi.perf_setup_time = ktime_get();
15996 +}
15997 +
15998 +static void perf_mark_start(void)
15999 +{
16000 + rfbi.perf_start_time = ktime_get();
16001 +}
16002 +
16003 +static void perf_show(const char *name)
16004 +{
16005 + ktime_t t, setup_time, trans_time;
16006 + u32 total_bytes;
16007 + u32 setup_us, trans_us, total_us;
16008 +
16009 + t = ktime_get();
16010 +
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)
16014 + setup_us = 1;
16015 +
16016 + trans_time = ktime_sub(t, rfbi.perf_start_time);
16017 + trans_us = (u32)ktime_to_us(trans_time);
16018 + if (trans_us == 0)
16019 + trans_us = 1;
16020 +
16021 + total_us = setup_us + trans_us;
16022 +
16023 + total_bytes = rfbi.perf_bytes;
16024 +
16025 + DSSINFO("%s update %u us + %u us = %u us (%uHz), %u bytes, "
16026 + "%u kbytes/sec\n",
16027 + name,
16028 + setup_us,
16029 + trans_us,
16030 + total_us,
16031 + 1000*1000 / total_us,
16032 + total_bytes,
16033 + total_bytes * 1000 / total_us);
16034 +}
16035 +#else
16036 +#define perf_mark_setup()
16037 +#define perf_mark_start()
16038 +#define perf_show(x)
16039 +#endif
16040 +
16041 +void rfbi_transfer_area(u16 width, u16 height,
16042 + void (callback)(void *data), void *data)
16043 +{
16044 + u32 l;
16045 +
16046 + /*BUG_ON(callback == 0);*/
16047 + BUG_ON(rfbi.framedone_callback != NULL);
16048 +
16049 + DSSDBG("rfbi_transfer_area %dx%d\n", width, height);
16050 +
16051 + dispc_set_lcd_size(width, height);
16052 +
16053 + dispc_enable_lcd_out(1);
16054 +
16055 + rfbi.framedone_callback = callback;
16056 + rfbi.framedone_callback_data = data;
16057 +
16058 + rfbi_enable_clocks(1);
16059 +
16060 + rfbi_write_reg(RFBI_PIXEL_CNT, width * height);
16061 +
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 */
16066 +
16067 + perf_mark_start();
16068 +
16069 + rfbi_write_reg(RFBI_CONTROL, l);
16070 +}
16071 +
16072 +static void framedone_callback(void *data, u32 mask)
16073 +{
16074 + void (*callback)(void *data);
16075 +
16076 + DSSDBG("FRAMEDONE\n");
16077 +
16078 + perf_show("DISPC");
16079 +
16080 + REG_FLD_MOD(RFBI_CONTROL, 0, 0, 0);
16081 +
16082 + rfbi_enable_clocks(0);
16083 +
16084 + callback = rfbi.framedone_callback;
16085 + rfbi.framedone_callback = NULL;
16086 +
16087 + /*callback(rfbi.framedone_callback_data);*/
16088 +
16089 + atomic_set(&rfbi.cmd_pending, 0);
16090 +
16091 + process_cmd_fifo();
16092 +}
16093 +
16094 +#if 1 /* VERBOSE */
16095 +static void rfbi_print_timings(void)
16096 +{
16097 + u32 l;
16098 + u32 time;
16099 +
16100 + l = rfbi_read_reg(RFBI_CONFIG(0));
16101 + time = 1000000000 / rfbi.l4_khz;
16102 + if (l & (1 << 4))
16103 + time *= 2;
16104 +
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);
16111 +
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);
16117 +}
16118 +#else
16119 +static void rfbi_print_timings(void) {}
16120 +#endif
16121 +
16122 +
16123 +
16124 +
16125 +static u32 extif_clk_period;
16126 +
16127 +static inline unsigned long round_to_extif_ticks(unsigned long ps, int div)
16128 +{
16129 + int bus_tick = extif_clk_period * div;
16130 + return (ps + bus_tick - 1) / bus_tick * bus_tick;
16131 +}
16132 +
16133 +static int calc_reg_timing(struct rfbi_timings *t, int div)
16134 +{
16135 + t->clk_div = div;
16136 +
16137 + t->cs_on_time = round_to_extif_ticks(t->cs_on_time, div);
16138 +
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);
16142 +
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);
16146 +
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);
16150 +
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);
16158 +
16159 + return rfbi_convert_timings(t);
16160 +}
16161 +
16162 +static int calc_extif_timings(struct rfbi_timings *t)
16163 +{
16164 + u32 max_clk_div;
16165 + int div;
16166 +
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)
16170 + break;
16171 + }
16172 +
16173 + if (div <= max_clk_div)
16174 + return 0;
16175 +
16176 + DSSERR("can't setup timings\n");
16177 + return -1;
16178 +}
16179 +
16180 +
16181 +void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t)
16182 +{
16183 + int r;
16184 +
16185 + if (!t->converted) {
16186 + r = calc_extif_timings(t);
16187 + if (r < 0)
16188 + DSSERR("Failed to calc timings\n");
16189 + }
16190 +
16191 + BUG_ON(!t->converted);
16192 +
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]);
16196 +
16197 + /* TIMEGRANULARITY */
16198 + REG_FLD_MOD(RFBI_CONFIG(rfbi_module),
16199 + (t->tim[2] ? 1 : 0), 4, 4);
16200 +
16201 + rfbi_print_timings();
16202 + rfbi_enable_clocks(0);
16203 +}
16204 +
16205 +static int ps_to_rfbi_ticks(int time, int div)
16206 +{
16207 + unsigned long tick_ps;
16208 + int ret;
16209 +
16210 + /* Calculate in picosecs to yield more exact results */
16211 + tick_ps = 1000000000 / (rfbi.l4_khz) * div;
16212 +
16213 + ret = (time + tick_ps - 1) / tick_ps;
16214 +
16215 + return ret;
16216 +}
16217 +
16218 +#ifdef OMAP_RFBI_RATE_LIMIT
16219 +unsigned long rfbi_get_max_tx_rate(void)
16220 +{
16221 + unsigned long l4_rate, dss1_rate;
16222 + int min_l4_ticks = 0;
16223 + int i;
16224 +
16225 + /* According to TI this can't be calculated so make the
16226 + * adjustments for a couple of known frequencies and warn for
16227 + * others.
16228 + */
16229 + static const struct {
16230 + unsigned long l4_clk; /* HZ */
16231 + unsigned long dss1_clk; /* HZ */
16232 + unsigned long min_l4_ticks;
16233 + } ftab[] = {
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 */
16239 + };
16240 +
16241 + l4_rate = rfbi.l4_khz / 1000;
16242 + dss1_rate = dss_clk_get_rate(DSS_CLK_FCK1) / 1000000;
16243 +
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.
16247 + */
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;
16251 + break;
16252 + }
16253 + }
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.
16258 + */
16259 + DSSERR("can't determine maximum RFBI transfer rate\n");
16260 + return rfbi.l4_khz * 1000;
16261 + }
16262 + return rfbi.l4_khz * 1000 / min_l4_ticks;
16263 +}
16264 +#else
16265 +int rfbi_get_max_tx_rate(void)
16266 +{
16267 + return rfbi.l4_khz * 1000;
16268 +}
16269 +#endif
16270 +
16271 +static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div)
16272 +{
16273 + *clk_period = 1000000000 / rfbi.l4_khz;
16274 + *max_clk_div = 2;
16275 +}
16276 +
16277 +static int rfbi_convert_timings(struct rfbi_timings *t)
16278 +{
16279 + u32 l;
16280 + int reon, reoff, weon, weoff, cson, csoff, cs_pulse;
16281 + int actim, recyc, wecyc;
16282 + int div = t->clk_div;
16283 +
16284 + if (div <= 0 || div > 2)
16285 + return -1;
16286 +
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
16290 + */
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;
16295 + if (weon > 0x0f)
16296 + return -1;
16297 + if (weoff > 0x3f)
16298 + return -1;
16299 +
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;
16304 + if (reon > 0x0f)
16305 + return -1;
16306 + if (reoff > 0x3f)
16307 + return -1;
16308 +
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);
16315 + if (cson > 0x0f)
16316 + return -1;
16317 + if (csoff > 0x3f)
16318 + return -1;
16319 +
16320 + l = cson;
16321 + l |= csoff << 4;
16322 + l |= weon << 10;
16323 + l |= weoff << 14;
16324 + l |= reon << 20;
16325 + l |= reoff << 24;
16326 +
16327 + t->tim[0] = l;
16328 +
16329 + actim = ps_to_rfbi_ticks(t->access_time, div);
16330 + if (actim <= reon)
16331 + actim = reon + 1;
16332 + if (actim > 0x3f)
16333 + return -1;
16334 +
16335 + wecyc = ps_to_rfbi_ticks(t->we_cycle_time, div);
16336 + if (wecyc < weoff)
16337 + wecyc = weoff;
16338 + if (wecyc > 0x3f)
16339 + return -1;
16340 +
16341 + recyc = ps_to_rfbi_ticks(t->re_cycle_time, div);
16342 + if (recyc < reoff)
16343 + recyc = reoff;
16344 + if (recyc > 0x3f)
16345 + return -1;
16346 +
16347 + cs_pulse = ps_to_rfbi_ticks(t->cs_pulse_width, div);
16348 + if (cs_pulse > 0x3f)
16349 + return -1;
16350 +
16351 + l = wecyc;
16352 + l |= recyc << 6;
16353 + l |= cs_pulse << 12;
16354 + l |= actim << 22;
16355 +
16356 + t->tim[1] = l;
16357 +
16358 + t->tim[2] = div - 1;
16359 +
16360 + t->converted = 1;
16361 +
16362 + return 0;
16363 +}
16364 +
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)
16369 +{
16370 + int hs, vs;
16371 + int min;
16372 + u32 l;
16373 +
16374 + hs = ps_to_rfbi_ticks(hs_pulse_time, 1);
16375 + vs = ps_to_rfbi_ticks(vs_pulse_time, 1);
16376 + if (hs < 2)
16377 + return -EDOM;
16378 + if (mode == OMAP_DSS_RFBI_TE_MODE_2)
16379 + min = 2;
16380 + else /* OMAP_DSS_RFBI_TE_MODE_1 */
16381 + min = 4;
16382 + if (vs < min)
16383 + return -EDOM;
16384 + if (vs == hs)
16385 + return -EINVAL;
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);
16389 +
16390 + rfbi_enable_clocks(1);
16391 + rfbi_write_reg(RFBI_HSYNC_WIDTH, hs);
16392 + rfbi_write_reg(RFBI_VSYNC_WIDTH, vs);
16393 +
16394 + l = rfbi_read_reg(RFBI_CONFIG(0));
16395 + if (hs_pol_inv)
16396 + l &= ~(1 << 21);
16397 + else
16398 + l |= 1 << 21;
16399 + if (vs_pol_inv)
16400 + l &= ~(1 << 20);
16401 + else
16402 + l |= 1 << 20;
16403 + rfbi_enable_clocks(0);
16404 +
16405 + return 0;
16406 +}
16407 +EXPORT_SYMBOL(omap_rfbi_setup_te);
16408 +
16409 +/* xxx FIX module selection missing */
16410 +int omap_rfbi_enable_te(bool enable, unsigned line)
16411 +{
16412 + u32 l;
16413 +
16414 + DSSDBG("te %d line %d mode %d\n", enable, line, rfbi.te_mode);
16415 + if (line > (1 << 11) - 1)
16416 + return -EINVAL;
16417 +
16418 + rfbi_enable_clocks(1);
16419 + l = rfbi_read_reg(RFBI_CONFIG(0));
16420 + l &= ~(0x3 << 2);
16421 + if (enable) {
16422 + rfbi.te_enabled = 1;
16423 + l |= rfbi.te_mode << 2;
16424 + } else
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);
16429 +
16430 + return 0;
16431 +}
16432 +EXPORT_SYMBOL(omap_rfbi_enable_te);
16433 +
16434 +#if 0
16435 +static void rfbi_enable_config(int enable1, int enable2)
16436 +{
16437 + u32 l;
16438 + int cs = 0;
16439 +
16440 + if (enable1)
16441 + cs |= 1<<0;
16442 + if (enable2)
16443 + cs |= 1<<1;
16444 +
16445 + rfbi_enable_clocks(1);
16446 +
16447 + l = rfbi_read_reg(RFBI_CONTROL);
16448 +
16449 + l = FLD_MOD(l, cs, 3, 2);
16450 + l = FLD_MOD(l, 0, 1, 1);
16451 +
16452 + rfbi_write_reg(RFBI_CONTROL, l);
16453 +
16454 +
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 */
16459 +
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 */
16463 +
16464 + l = FLD_MOD(l, OMAP_DSS_RFBI_PARALLELMODE_8, 1, 0);
16465 + rfbi_write_reg(RFBI_CONFIG(0), l);
16466 +
16467 + rfbi_enable_clocks(0);
16468 +}
16469 +#endif
16470 +
16471 +int rfbi_configure(int rfbi_module, int bpp, int lines)
16472 +{
16473 + u32 l;
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;
16478 +
16479 + switch (bpp) {
16480 + case 12:
16481 + datatype = OMAP_DSS_RFBI_DATATYPE_12;
16482 + break;
16483 + case 16:
16484 + datatype = OMAP_DSS_RFBI_DATATYPE_16;
16485 + break;
16486 + case 18:
16487 + datatype = OMAP_DSS_RFBI_DATATYPE_18;
16488 + break;
16489 + case 24:
16490 + datatype = OMAP_DSS_RFBI_DATATYPE_24;
16491 + break;
16492 + default:
16493 + BUG();
16494 + return 1;
16495 + }
16496 + rfbi.datatype = datatype;
16497 +
16498 + switch (lines) {
16499 + case 8:
16500 + parallelmode = OMAP_DSS_RFBI_PARALLELMODE_8;
16501 + break;
16502 + case 9:
16503 + parallelmode = OMAP_DSS_RFBI_PARALLELMODE_9;
16504 + break;
16505 + case 12:
16506 + parallelmode = OMAP_DSS_RFBI_PARALLELMODE_12;
16507 + break;
16508 + case 16:
16509 + parallelmode = OMAP_DSS_RFBI_PARALLELMODE_16;
16510 + break;
16511 + default:
16512 + BUG();
16513 + return 1;
16514 + }
16515 + rfbi.parallelmode = parallelmode;
16516 +
16517 + if ((bpp % lines) == 0) {
16518 + switch (bpp / lines) {
16519 + case 1:
16520 + cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_1_1;
16521 + break;
16522 + case 2:
16523 + cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_2_1;
16524 + break;
16525 + case 3:
16526 + cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_3_1;
16527 + break;
16528 + default:
16529 + BUG();
16530 + return 1;
16531 + }
16532 + } else if ((2 * bpp % lines) == 0) {
16533 + if ((2 * bpp / lines) == 3)
16534 + cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_3_2;
16535 + else {
16536 + BUG();
16537 + return 1;
16538 + }
16539 + } else {
16540 + BUG();
16541 + return 1;
16542 + }
16543 +
16544 + switch (cycleformat) {
16545 + case OMAP_DSS_RFBI_CYCLEFORMAT_1_1:
16546 + cycle1 = lines;
16547 + break;
16548 +
16549 + case OMAP_DSS_RFBI_CYCLEFORMAT_2_1:
16550 + cycle1 = lines;
16551 + cycle2 = lines;
16552 + break;
16553 +
16554 + case OMAP_DSS_RFBI_CYCLEFORMAT_3_1:
16555 + cycle1 = lines;
16556 + cycle2 = lines;
16557 + cycle3 = lines;
16558 + break;
16559 +
16560 + case OMAP_DSS_RFBI_CYCLEFORMAT_3_2:
16561 + cycle1 = lines;
16562 + cycle2 = (lines / 2) | ((lines / 2) << 16);
16563 + cycle3 = (lines << 16);
16564 + break;
16565 + }
16566 +
16567 + rfbi_enable_clocks(1);
16568 +
16569 + REG_FLD_MOD(RFBI_CONTROL, 0, 3, 2); /* clear CS */
16570 +
16571 + l = 0;
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);
16587 +
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);
16591 +
16592 +
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);
16597 +
16598 +
16599 + DSSDBG("RFBI config: bpp %d, lines %d, cycles: 0x%x 0x%x 0x%x\n",
16600 + bpp, lines, cycle1, cycle2, cycle3);
16601 +
16602 + rfbi_enable_clocks(0);
16603 +
16604 + return 0;
16605 +}
16606 +EXPORT_SYMBOL(rfbi_configure);
16607 +
16608 +static int rfbi_find_display(struct omap_dss_device *dssdev)
16609 +{
16610 + if (dssdev == rfbi.dssdev[0])
16611 + return 0;
16612 +
16613 + if (dssdev == rfbi.dssdev[1])
16614 + return 1;
16615 +
16616 + BUG();
16617 + return -1;
16618 +}
16619 +
16620 +
16621 +static void signal_fifo_waiters(void)
16622 +{
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);
16627 + }
16628 +}
16629 +
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)
16632 +{
16633 + u16 x = upd->x;
16634 + u16 y = upd->y;
16635 + u16 w = upd->w;
16636 + u16 h = upd->h;
16637 +
16638 + perf_mark_setup();
16639 +
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);
16643 + }
16644 +
16645 +#ifdef MEASURE_PERF
16646 + rfbi.perf_bytes = w * h * 2; /* XXX always 16bit */
16647 +#endif
16648 +
16649 + dssdev->driver->setup_update(dssdev, x, y, w, h);
16650 +
16651 + if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
16652 + rfbi_transfer_area(w, h, NULL, NULL);
16653 + return 1;
16654 + } else {
16655 + struct omap_overlay *ovl;
16656 + void __iomem *addr;
16657 + int scr_width;
16658 +
16659 + ovl = dssdev->manager->overlays[0];
16660 + scr_width = ovl->info.screen_width;
16661 + addr = ovl->info.vaddr;
16662 +
16663 + omap_rfbi_write_pixels(addr, scr_width, x, y, w, h);
16664 +
16665 + perf_show("L4");
16666 +
16667 + return 0;
16668 + }
16669 +}
16670 +
16671 +static void process_cmd_fifo(void)
16672 +{
16673 + int len;
16674 + struct update_param p;
16675 + struct omap_dss_device *dssdev;
16676 + unsigned long flags;
16677 +
16678 + if (atomic_inc_return(&rfbi.cmd_pending) != 1)
16679 + return;
16680 +
16681 + while (true) {
16682 + spin_lock_irqsave(rfbi.cmd_fifo->lock, flags);
16683 +
16684 + len = __kfifo_get(rfbi.cmd_fifo, (unsigned char *)&p,
16685 + sizeof(struct update_param));
16686 + if (len == 0) {
16687 + DSSDBG("nothing more in fifo\n");
16688 + atomic_set(&rfbi.cmd_pending, 0);
16689 + spin_unlock_irqrestore(rfbi.cmd_fifo->lock, flags);
16690 + break;
16691 + }
16692 +
16693 + /* DSSDBG("fifo full %d\n", rfbi.cmd_fifo_full.counter);*/
16694 +
16695 + spin_unlock_irqrestore(rfbi.cmd_fifo->lock, flags);
16696 +
16697 + BUG_ON(len != sizeof(struct update_param));
16698 + BUG_ON(p.rfbi_module > 1);
16699 +
16700 + dssdev = rfbi.dssdev[p.rfbi_module];
16701 +
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);
16708 + } else
16709 + BUG();
16710 + }
16711 +
16712 + signal_fifo_waiters();
16713 +}
16714 +
16715 +static void rfbi_push_cmd(struct update_param *p)
16716 +{
16717 + int ret;
16718 +
16719 + while (1) {
16720 + unsigned long flags;
16721 + int available;
16722 +
16723 + spin_lock_irqsave(rfbi.cmd_fifo->lock, flags);
16724 + available = RFBI_CMD_FIFO_LEN_BYTES -
16725 + __kfifo_len(rfbi.cmd_fifo);
16726 +
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");*/
16734 + continue;
16735 + }
16736 +
16737 + ret = __kfifo_put(rfbi.cmd_fifo, (unsigned char *)p,
16738 + sizeof(struct update_param));
16739 +/* DSSDBG("pushed %d bytes\n", ret);*/
16740 +
16741 + spin_unlock_irqrestore(rfbi.cmd_fifo->lock, flags);
16742 +
16743 + BUG_ON(ret != sizeof(struct update_param));
16744 +
16745 + break;
16746 + }
16747 +}
16748 +
16749 +static void rfbi_push_update(int rfbi_module, int x, int y, int w, int h)
16750 +{
16751 + struct update_param p;
16752 +
16753 + p.rfbi_module = rfbi_module;
16754 + p.cmd = RFBI_CMD_UPDATE;
16755 +
16756 + p.par.r.x = x;
16757 + p.par.r.y = y;
16758 + p.par.r.w = w;
16759 + p.par.r.h = h;
16760 +
16761 + DSSDBG("RFBI pushed %d,%d %dx%d\n", x, y, w, h);
16762 +
16763 + rfbi_push_cmd(&p);
16764 +
16765 + process_cmd_fifo();
16766 +}
16767 +
16768 +static void rfbi_push_sync(int rfbi_module, struct completion *sync_comp)
16769 +{
16770 + struct update_param p;
16771 +
16772 + p.rfbi_module = rfbi_module;
16773 + p.cmd = RFBI_CMD_SYNC;
16774 + p.par.sync = sync_comp;
16775 +
16776 + rfbi_push_cmd(&p);
16777 +
16778 + DSSDBG("RFBI sync pushed to cmd fifo\n");
16779 +
16780 + process_cmd_fifo();
16781 +}
16782 +
16783 +void rfbi_dump_regs(struct seq_file *s)
16784 +{
16785 +#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, rfbi_read_reg(r))
16786 +
16787 + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
16788 +
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);
16800 +
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));
16807 +
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));
16814 +
16815 + DUMPREG(RFBI_VSYNC_WIDTH);
16816 + DUMPREG(RFBI_HSYNC_WIDTH);
16817 +
16818 + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
16819 +#undef DUMPREG
16820 +}
16821 +
16822 +int rfbi_init(void)
16823 +{
16824 + u32 rev;
16825 + u32 l;
16826 +
16827 + spin_lock_init(&rfbi.cmd_lock);
16828 + rfbi.cmd_fifo = kfifo_alloc(RFBI_CMD_FIFO_LEN_BYTES, GFP_KERNEL,
16829 + &rfbi.cmd_lock);
16830 + if (IS_ERR(rfbi.cmd_fifo))
16831 + return -ENOMEM;
16832 +
16833 + init_completion(&rfbi.cmd_done);
16834 + atomic_set(&rfbi.cmd_fifo_full, 0);
16835 + atomic_set(&rfbi.cmd_pending, 0);
16836 +
16837 + rfbi.base = ioremap(RFBI_BASE, SZ_256);
16838 + if (!rfbi.base) {
16839 + DSSERR("can't ioremap RFBI\n");
16840 + return -ENOMEM;
16841 + }
16842 +
16843 + rfbi_enable_clocks(1);
16844 +
16845 + msleep(10);
16846 +
16847 + rfbi.l4_khz = dss_clk_get_rate(DSS_CLK_ICK) / 1000;
16848 +
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);
16853 +
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));
16857 +
16858 + rfbi_enable_clocks(0);
16859 +
16860 + return 0;
16861 +}
16862 +
16863 +void rfbi_exit(void)
16864 +{
16865 + DSSDBG("rfbi_exit\n");
16866 +
16867 + kfifo_free(rfbi.cmd_fifo);
16868 +
16869 + iounmap(rfbi.base);
16870 +}
16871 +
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)
16875 +{
16876 + int rfbi_module;
16877 +
16878 + if (w == 0 || h == 0)
16879 + return 0;
16880 +
16881 + rfbi_module = rfbi_find_display(dssdev);
16882 +
16883 + rfbi_push_update(rfbi_module, x, y, w, h);
16884 +
16885 + return 0;
16886 +}
16887 +
16888 +static int rfbi_display_sync(struct omap_dss_device *dssdev)
16889 +{
16890 + struct completion sync_comp;
16891 + int rfbi_module;
16892 +
16893 + rfbi_module = rfbi_find_display(dssdev);
16894 +
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");
16900 + return 0;
16901 +}
16902 +
16903 +static int rfbi_display_enable_te(struct omap_dss_device *dssdev, bool enable)
16904 +{
16905 + dssdev->driver->enable_te(dssdev, enable);
16906 + return 0;
16907 +}
16908 +
16909 +static int rfbi_display_enable(struct omap_dss_device *dssdev)
16910 +{
16911 + int r;
16912 +
16913 + r = omap_dss_start_device(dssdev);
16914 + if (r) {
16915 + DSSERR("failed to start device\n");
16916 + goto err0;
16917 + }
16918 +
16919 + r = omap_dispc_register_isr(framedone_callback, NULL,
16920 + DISPC_IRQ_FRAMEDONE);
16921 + if (r) {
16922 + DSSERR("can't get FRAMEDONE irq\n");
16923 + goto err1;
16924 + }
16925 +
16926 + dispc_set_lcd_display_type(OMAP_DSS_LCD_DISPLAY_TFT);
16927 +
16928 + dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_RFBI);
16929 +
16930 + dispc_set_tft_data_lines(dssdev->ctrl.pixel_size);
16931 +
16932 + rfbi_configure(dssdev->phy.rfbi.channel,
16933 + dssdev->ctrl.pixel_size,
16934 + dssdev->phy.rfbi.data_lines);
16935 +
16936 + rfbi_set_timings(dssdev->phy.rfbi.channel,
16937 + &dssdev->ctrl.rfbi_timings);
16938 +
16939 +
16940 + if (dssdev->driver->enable) {
16941 + r = dssdev->driver->enable(dssdev);
16942 + if (r)
16943 + goto err2;
16944 + }
16945 +
16946 + return 0;
16947 +err2:
16948 + omap_dispc_unregister_isr(framedone_callback, NULL,
16949 + DISPC_IRQ_FRAMEDONE);
16950 +err1:
16951 + omap_dss_stop_device(dssdev);
16952 +err0:
16953 + return r;
16954 +}
16955 +
16956 +static void rfbi_display_disable(struct omap_dss_device *dssdev)
16957 +{
16958 + dssdev->driver->disable(dssdev);
16959 + omap_dispc_unregister_isr(framedone_callback, NULL,
16960 + DISPC_IRQ_FRAMEDONE);
16961 + omap_dss_stop_device(dssdev);
16962 +}
16963 +
16964 +int rfbi_init_display(struct omap_dss_device *dssdev)
16965 +{
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;
16971 +
16972 + rfbi.dssdev[dssdev->phy.rfbi.channel] = dssdev;
16973 +
16974 + dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
16975 +
16976 + return 0;
16977 +}
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
16981 --- /dev/null
16982 +++ b/drivers/video/omap2/dss/sdi.c
16983 @@ -0,0 +1,261 @@
16984 +/*
16985 + * linux/drivers/video/omap2/dss/sdi.c
16986 + *
16987 + * Copyright (C) 2009 Nokia Corporation
16988 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
16989 + *
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.
16993 + *
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
16997 + * more details.
16998 + *
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/>.
17001 + */
17002 +
17003 +#define DSS_SUBSYS_NAME "SDI"
17004 +
17005 +#include <linux/kernel.h>
17006 +#include <linux/clk.h>
17007 +#include <linux/delay.h>
17008 +#include <linux/err.h>
17009 +
17010 +#include <mach/board.h>
17011 +#include <mach/display.h>
17012 +#include "dss.h"
17013 +
17014 +static struct {
17015 + bool skip_init;
17016 + bool update_enabled;
17017 +} sdi;
17018 +
17019 +static void sdi_basic_init(void)
17020 +{
17021 + dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_BYPASS);
17022 +
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);
17026 +}
17027 +
17028 +static int sdi_display_enable(struct omap_dss_device *dssdev)
17029 +{
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;
17035 + int r;
17036 +
17037 + r = omap_dss_start_device(dssdev);
17038 + if (r) {
17039 + DSSERR("failed to start device\n");
17040 + goto err0;
17041 + }
17042 +
17043 + if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
17044 + DSSERR("dssdev already enabled\n");
17045 + r = -EINVAL;
17046 + goto err1;
17047 + }
17048 +
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);
17052 +
17053 + sdi_basic_init();
17054 +
17055 + /* 15.5.9.1.2 */
17056 + dssdev->panel.config |= OMAP_DSS_LCD_RF | OMAP_DSS_LCD_ONOFF;
17057 +
17058 + dispc_set_pol_freq(dssdev->panel.config, dssdev->panel.acbi,
17059 + dssdev->panel.acb);
17060 +
17061 + if (!sdi.skip_init)
17062 + r = dispc_calc_clock_div(1, t->pixel_clock * 1000,
17063 + &cinfo);
17064 + else
17065 + r = dispc_get_clock_div(&cinfo);
17066 +
17067 + if (r)
17068 + goto err2;
17069 +
17070 + fck = cinfo.fck;
17071 + lck_div = cinfo.lck_div;
17072 + pck_div = cinfo.pck_div;
17073 +
17074 + pck = fck / lck_div / pck_div / 1000;
17075 +
17076 + if (pck != t->pixel_clock) {
17077 + DSSWARN("Could not find exact pixel clock. Requested %d kHz, "
17078 + "got %lu kHz\n",
17079 + t->pixel_clock, pck);
17080 +
17081 + t->pixel_clock = pck;
17082 + }
17083 +
17084 +
17085 + dispc_set_lcd_timings(t);
17086 +
17087 + r = dispc_set_clock_div(&cinfo);
17088 + if (r)
17089 + goto err2;
17090 +
17091 + if (!sdi.skip_init) {
17092 + dss_sdi_init(dssdev->phy.sdi.datapairs);
17093 + dss_sdi_enable();
17094 + mdelay(2);
17095 + }
17096 +
17097 + dispc_enable_lcd_out(1);
17098 +
17099 + if (dssdev->driver->enable) {
17100 + r = dssdev->driver->enable(dssdev);
17101 + if (r)
17102 + goto err3;
17103 + }
17104 +
17105 + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
17106 +
17107 + sdi.skip_init = 0;
17108 +
17109 + return 0;
17110 +err3:
17111 + dispc_enable_lcd_out(0);
17112 +err2:
17113 + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
17114 +err1:
17115 + omap_dss_stop_device(dssdev);
17116 +err0:
17117 + return r;
17118 +}
17119 +
17120 +static int sdi_display_resume(struct omap_dss_device *dssdev);
17121 +
17122 +static void sdi_display_disable(struct omap_dss_device *dssdev)
17123 +{
17124 + if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED)
17125 + return;
17126 +
17127 + if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED)
17128 + sdi_display_resume(dssdev);
17129 +
17130 + if (dssdev->driver->disable)
17131 + dssdev->driver->disable(dssdev);
17132 +
17133 + dispc_enable_lcd_out(0);
17134 +
17135 + dss_sdi_disable();
17136 +
17137 + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
17138 +
17139 + dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
17140 +
17141 + omap_dss_stop_device(dssdev);
17142 +}
17143 +
17144 +static int sdi_display_suspend(struct omap_dss_device *dssdev)
17145 +{
17146 + if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
17147 + return -EINVAL;
17148 +
17149 + if (dssdev->driver->suspend)
17150 + dssdev->driver->suspend(dssdev);
17151 +
17152 + dispc_enable_lcd_out(0);
17153 +
17154 + dss_sdi_disable();
17155 +
17156 + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
17157 +
17158 + dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
17159 +
17160 + return 0;
17161 +}
17162 +
17163 +static int sdi_display_resume(struct omap_dss_device *dssdev)
17164 +{
17165 + if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED)
17166 + return -EINVAL;
17167 +
17168 + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
17169 +
17170 + dss_sdi_enable();
17171 + mdelay(2);
17172 +
17173 + dispc_enable_lcd_out(1);
17174 +
17175 + if (dssdev->driver->resume)
17176 + dssdev->driver->resume(dssdev);
17177 +
17178 + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
17179 +
17180 + return 0;
17181 +}
17182 +
17183 +static int sdi_display_set_update_mode(struct omap_dss_device *dssdev,
17184 + enum omap_dss_update_mode mode)
17185 +{
17186 + if (mode == OMAP_DSS_UPDATE_MANUAL)
17187 + return -EINVAL;
17188 +
17189 + if (mode == OMAP_DSS_UPDATE_DISABLED) {
17190 + dispc_enable_lcd_out(0);
17191 + sdi.update_enabled = 0;
17192 + } else {
17193 + dispc_enable_lcd_out(1);
17194 + sdi.update_enabled = 1;
17195 + }
17196 +
17197 + return 0;
17198 +}
17199 +
17200 +static enum omap_dss_update_mode sdi_display_get_update_mode(
17201 + struct omap_dss_device *dssdev)
17202 +{
17203 + return sdi.update_enabled ? OMAP_DSS_UPDATE_AUTO :
17204 + OMAP_DSS_UPDATE_DISABLED;
17205 +}
17206 +
17207 +static void sdi_get_timings(struct omap_dss_device *dssdev,
17208 + struct omap_video_timings *timings)
17209 +{
17210 + *timings = dssdev->panel.timings;
17211 +}
17212 +
17213 +int sdi_init_display(struct omap_dss_device *dssdev)
17214 +{
17215 + DSSDBG("SDI init\n");
17216 +
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;
17224 +
17225 + return 0;
17226 +}
17227 +
17228 +int sdi_init(bool skip_init)
17229 +{
17230 + /* we store this for first display enable, then clear it */
17231 + sdi.skip_init = skip_init;
17232 +
17233 + /*
17234 + * Enable clocks already here, otherwise there would be a toggle
17235 + * of them until sdi_display_enable is called.
17236 + */
17237 + if (skip_init)
17238 + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
17239 + return 0;
17240 +}
17241 +
17242 +void sdi_exit(void)
17243 +{
17244 +}
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
17248 --- /dev/null
17249 +++ b/drivers/video/omap2/dss/venc.c
17250 @@ -0,0 +1,797 @@
17251 +/*
17252 + * linux/drivers/video/omap2/dss/venc.c
17253 + *
17254 + * Copyright (C) 2009 Nokia Corporation
17255 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
17256 + *
17257 + * VENC settings from TI's DSS driver
17258 + *
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.
17262 + *
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
17266 + * more details.
17267 + *
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/>.
17270 + */
17271 +
17272 +#define DSS_SUBSYS_NAME "VENC"
17273 +
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>
17286 +
17287 +#include <mach/display.h>
17288 +#include <mach/cpu.h>
17289 +
17290 +#include "dss.h"
17291 +
17292 +#define VENC_BASE 0x48050C00
17293 +
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
17339 +
17340 +struct venc_config {
17341 + u32 f_control;
17342 + u32 vidout_ctrl;
17343 + u32 sync_ctrl;
17344 + u32 llen;
17345 + u32 flens;
17346 + u32 hfltr_ctrl;
17347 + u32 cc_carr_wss_carr;
17348 + u32 c_phase;
17349 + u32 gain_u;
17350 + u32 gain_v;
17351 + u32 gain_y;
17352 + u32 black_level;
17353 + u32 blank_level;
17354 + u32 x_color;
17355 + u32 m_control;
17356 + u32 bstamp_wss_data;
17357 + u32 s_carr;
17358 + u32 line21;
17359 + u32 ln_sel;
17360 + u32 l21__wc_ctl;
17361 + u32 htrigger_vtrigger;
17362 + u32 savid__eavid;
17363 + u32 flen__fal;
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;
17379 + u32 gen_ctrl;
17380 +};
17381 +
17382 +/* from TRM */
17383 +static const struct venc_config venc_config_pal_trm = {
17384 + .f_control = 0,
17385 + .vidout_ctrl = 1,
17386 + .sync_ctrl = 0x40,
17387 + .llen = 0x35F, /* 863 */
17388 + .flens = 0x270, /* 624 */
17389 + .hfltr_ctrl = 0,
17390 + .cc_carr_wss_carr = 0x2F7225ED,
17391 + .c_phase = 0,
17392 + .gain_u = 0x111,
17393 + .gain_v = 0x181,
17394 + .gain_y = 0x140,
17395 + .black_level = 0x3B,
17396 + .blank_level = 0x3B,
17397 + .x_color = 0x7,
17398 + .m_control = 0x2,
17399 + .bstamp_wss_data = 0x3F,
17400 + .s_carr = 0x2A098ACB,
17401 + .line21 = 0,
17402 + .ln_sel = 0x01290015,
17403 + .l21__wc_ctl = 0x0000F603,
17404 + .htrigger_vtrigger = 0,
17405 +
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,
17421 +
17422 + .tvdetgp_int_start_stop_x = 0x00140001,
17423 + .tvdetgp_int_start_stop_y = 0x00010001,
17424 + .gen_ctrl = 0x00FF0000,
17425 +};
17426 +
17427 +/* from TRM */
17428 +static const struct venc_config venc_config_ntsc_trm = {
17429 + .f_control = 0,
17430 + .vidout_ctrl = 1,
17431 + .sync_ctrl = 0x8040,
17432 + .llen = 0x359,
17433 + .flens = 0x20C,
17434 + .hfltr_ctrl = 0,
17435 + .cc_carr_wss_carr = 0x043F2631,
17436 + .c_phase = 0,
17437 + .gain_u = 0x102,
17438 + .gain_v = 0x16C,
17439 + .gain_y = 0x12F,
17440 + .black_level = 0x43,
17441 + .blank_level = 0x38,
17442 + .x_color = 0x7,
17443 + .m_control = 0x1,
17444 + .bstamp_wss_data = 0x38,
17445 + .s_carr = 0x21F07C1F,
17446 + .line21 = 0,
17447 + .ln_sel = 0x01310011,
17448 + .l21__wc_ctl = 0x0000F003,
17449 + .htrigger_vtrigger = 0,
17450 +
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,
17466 +
17467 + .tvdetgp_int_start_stop_x = 0x00140001,
17468 + .tvdetgp_int_start_stop_y = 0x00010001,
17469 + .gen_ctrl = 0x00F90000,
17470 +};
17471 +
17472 +static const struct venc_config venc_config_pal_bdghi = {
17473 + .f_control = 0,
17474 + .vidout_ctrl = 0,
17475 + .sync_ctrl = 0,
17476 + .hfltr_ctrl = 0,
17477 + .x_color = 0,
17478 + .line21 = 0,
17479 + .ln_sel = 21,
17480 + .htrigger_vtrigger = 0,
17481 + .tvdetgp_int_start_stop_x = 0x00140001,
17482 + .tvdetgp_int_start_stop_y = 0x00010001,
17483 + .gen_ctrl = 0x00FB0000,
17484 +
17485 + .llen = 864-1,
17486 + .flens = 625-1,
17487 + .cc_carr_wss_carr = 0x2F7625ED,
17488 + .c_phase = 0xDF,
17489 + .gain_u = 0x111,
17490 + .gain_v = 0x181,
17491 + .gain_y = 0x140,
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,
17513 +};
17514 +
17515 +const struct omap_video_timings omap_dss_pal_timings = {
17516 + .x_res = 720,
17517 + .y_res = 574,
17518 + .pixel_clock = 13500,
17519 + .hsw = 64,
17520 + .hfp = 12,
17521 + .hbp = 68,
17522 + .vsw = 5,
17523 + .vfp = 5,
17524 + .vbp = 41,
17525 +};
17526 +EXPORT_SYMBOL(omap_dss_pal_timings);
17527 +
17528 +const struct omap_video_timings omap_dss_ntsc_timings = {
17529 + .x_res = 720,
17530 + .y_res = 482,
17531 + .pixel_clock = 13500,
17532 + .hsw = 64,
17533 + .hfp = 16,
17534 + .hbp = 58,
17535 + .vsw = 6,
17536 + .vfp = 6,
17537 + .vbp = 31,
17538 +};
17539 +EXPORT_SYMBOL(omap_dss_ntsc_timings);
17540 +
17541 +static struct {
17542 + void __iomem *base;
17543 + struct mutex venc_lock;
17544 + u32 wss_data;
17545 + struct regulator *vdda_dac_reg;
17546 +} venc;
17547 +
17548 +static inline void venc_write_reg(int idx, u32 val)
17549 +{
17550 + __raw_writel(val, venc.base + idx);
17551 +}
17552 +
17553 +static inline u32 venc_read_reg(int idx)
17554 +{
17555 + u32 l = __raw_readl(venc.base + idx);
17556 + return l;
17557 +}
17558 +
17559 +static void venc_write_config(const struct venc_config *config)
17560 +{
17561 + DSSDBG("write venc conf\n");
17562 +
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 |
17574 + venc.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);
17598 +
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);
17613 +}
17614 +
17615 +static void venc_reset(void)
17616 +{
17617 + int t = 1000;
17618 +
17619 + venc_write_reg(VENC_F_CONTROL, 1<<8);
17620 + while (venc_read_reg(VENC_F_CONTROL) & (1<<8)) {
17621 + if (--t == 0) {
17622 + DSSERR("Failed to reset venc\n");
17623 + return;
17624 + }
17625 + }
17626 +
17627 + /* the magical sleep that makes things work */
17628 + msleep(20);
17629 +}
17630 +
17631 +static void venc_enable_clocks(int enable)
17632 +{
17633 + if (enable)
17634 + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_54M |
17635 + DSS_CLK_96M);
17636 + else
17637 + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_54M |
17638 + DSS_CLK_96M);
17639 +}
17640 +
17641 +static const struct venc_config *venc_timings_to_config(
17642 + struct omap_video_timings *timings)
17643 +{
17644 + if (memcmp(&omap_dss_pal_timings, timings, sizeof(*timings)) == 0)
17645 + return &venc_config_pal_trm;
17646 +
17647 + if (memcmp(&omap_dss_ntsc_timings, timings, sizeof(*timings)) == 0)
17648 + return &venc_config_ntsc_trm;
17649 +
17650 + BUG();
17651 +}
17652 +
17653 +
17654 +
17655 +
17656 +
17657 +/* driver */
17658 +static int venc_panel_probe(struct omap_dss_device *dssdev)
17659 +{
17660 + dssdev->panel.timings = omap_dss_pal_timings;
17661 +
17662 + return 0;
17663 +}
17664 +
17665 +static void venc_panel_remove(struct omap_dss_device *dssdev)
17666 +{
17667 +}
17668 +
17669 +static int venc_panel_enable(struct omap_dss_device *dssdev)
17670 +{
17671 + int r = 0;
17672 +
17673 + /* wait couple of vsyncs until enabling the LCD */
17674 + msleep(50);
17675 +
17676 + if (dssdev->platform_enable)
17677 + r = dssdev->platform_enable(dssdev);
17678 +
17679 + return r;
17680 +}
17681 +
17682 +static void venc_panel_disable(struct omap_dss_device *dssdev)
17683 +{
17684 + if (dssdev->platform_disable)
17685 + dssdev->platform_disable(dssdev);
17686 +
17687 + /* wait at least 5 vsyncs after disabling the LCD */
17688 +
17689 + msleep(100);
17690 +}
17691 +
17692 +static int venc_panel_suspend(struct omap_dss_device *dssdev)
17693 +{
17694 + venc_panel_disable(dssdev);
17695 + return 0;
17696 +}
17697 +
17698 +static int venc_panel_resume(struct omap_dss_device *dssdev)
17699 +{
17700 + return venc_panel_enable(dssdev);
17701 +}
17702 +
17703 +static struct omap_dss_driver venc_driver = {
17704 + .probe = venc_panel_probe,
17705 + .remove = venc_panel_remove,
17706 +
17707 + .enable = venc_panel_enable,
17708 + .disable = venc_panel_disable,
17709 + .suspend = venc_panel_suspend,
17710 + .resume = venc_panel_resume,
17711 +
17712 + .driver = {
17713 + .name = "venc",
17714 + .owner = THIS_MODULE,
17715 + },
17716 +};
17717 +/* driver end */
17718 +
17719 +
17720 +
17721 +int venc_init(struct platform_device *pdev)
17722 +{
17723 + u8 rev_id;
17724 +
17725 + mutex_init(&venc.venc_lock);
17726 +
17727 + venc.wss_data = 0;
17728 +
17729 + venc.base = ioremap(VENC_BASE, SZ_1K);
17730 + if (!venc.base) {
17731 + DSSERR("can't ioremap VENC\n");
17732 + return -ENOMEM;
17733 + }
17734 +
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);
17740 + }
17741 +
17742 + venc_enable_clocks(1);
17743 +
17744 + rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff);
17745 + printk(KERN_INFO "OMAP VENC rev %d\n", rev_id);
17746 +
17747 + venc_enable_clocks(0);
17748 +
17749 + return omap_dss_register_driver(&venc_driver);
17750 +}
17751 +
17752 +void venc_exit(void)
17753 +{
17754 + omap_dss_unregister_driver(&venc_driver);
17755 +
17756 + regulator_put(venc.vdda_dac_reg);
17757 +
17758 + iounmap(venc.base);
17759 +}
17760 +
17761 +static void venc_power_on(struct omap_dss_device *dssdev)
17762 +{
17763 + u32 l;
17764 +
17765 + venc_enable_clocks(1);
17766 +
17767 + venc_reset();
17768 + venc_write_config(venc_timings_to_config(&dssdev->panel.timings));
17769 +
17770 + dss_set_venc_output(dssdev->phy.venc.type);
17771 + dss_set_dac_pwrdn_bgz(1);
17772 +
17773 + l = 0;
17774 +
17775 + if (dssdev->phy.venc.type == OMAP_DSS_VENC_TYPE_COMPOSITE)
17776 + l |= 1 << 1;
17777 + else /* S-Video */
17778 + l |= (1 << 0) | (1 << 2);
17779 +
17780 + if (dssdev->phy.venc.invert_polarity == false)
17781 + l |= 1 << 3;
17782 +
17783 + venc_write_reg(VENC_OUTPUT_CONTROL, l);
17784 +
17785 + dispc_set_digit_size(dssdev->panel.timings.x_res,
17786 + dssdev->panel.timings.y_res/2);
17787 +
17788 + regulator_enable(venc.vdda_dac_reg);
17789 +
17790 + if (dssdev->platform_enable)
17791 + dssdev->platform_enable(dssdev);
17792 +
17793 + dispc_enable_digit_out(1);
17794 +}
17795 +
17796 +static void venc_power_off(struct omap_dss_device *dssdev)
17797 +{
17798 + venc_write_reg(VENC_OUTPUT_CONTROL, 0);
17799 + dss_set_dac_pwrdn_bgz(0);
17800 +
17801 + dispc_enable_digit_out(0);
17802 +
17803 + if (dssdev->platform_disable)
17804 + dssdev->platform_disable(dssdev);
17805 +
17806 + regulator_disable(venc.vdda_dac_reg);
17807 +
17808 + venc_enable_clocks(0);
17809 +}
17810 +
17811 +static int venc_enable_display(struct omap_dss_device *dssdev)
17812 +{
17813 + int r = 0;
17814 +
17815 + DSSDBG("venc_enable_display\n");
17816 +
17817 + mutex_lock(&venc.venc_lock);
17818 +
17819 + if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
17820 + r = -EINVAL;
17821 + goto err;
17822 + }
17823 +
17824 + venc_power_on(dssdev);
17825 +
17826 + venc.wss_data = 0;
17827 +
17828 + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
17829 +err:
17830 + mutex_unlock(&venc.venc_lock);
17831 +
17832 + return r;
17833 +}
17834 +
17835 +static void venc_disable_display(struct omap_dss_device *dssdev)
17836 +{
17837 + DSSDBG("venc_disable_display\n");
17838 +
17839 + mutex_lock(&venc.venc_lock);
17840 +
17841 + if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED)
17842 + goto end;
17843 +
17844 + if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) {
17845 + /* suspended is the same as disabled with venc */
17846 + dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
17847 + goto end;
17848 + }
17849 +
17850 + venc_power_off(dssdev);
17851 +
17852 + dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
17853 +end:
17854 + mutex_unlock(&venc.venc_lock);
17855 +}
17856 +
17857 +static int venc_display_suspend(struct omap_dss_device *dssdev)
17858 +{
17859 + int r = 0;
17860 +
17861 + DSSDBG("venc_display_suspend\n");
17862 +
17863 + mutex_lock(&venc.venc_lock);
17864 +
17865 + if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
17866 + r = -EINVAL;
17867 + goto err;
17868 + }
17869 +
17870 + venc_power_off(dssdev);
17871 +
17872 + dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
17873 +err:
17874 + mutex_unlock(&venc.venc_lock);
17875 +
17876 + return r;
17877 +}
17878 +
17879 +static int venc_display_resume(struct omap_dss_device *dssdev)
17880 +{
17881 + int r = 0;
17882 +
17883 + DSSDBG("venc_display_resume\n");
17884 +
17885 + mutex_lock(&venc.venc_lock);
17886 +
17887 + if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) {
17888 + r = -EINVAL;
17889 + goto err;
17890 + }
17891 +
17892 + venc_power_on(dssdev);
17893 +
17894 + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
17895 +err:
17896 + mutex_unlock(&venc.venc_lock);
17897 +
17898 + return r;
17899 +}
17900 +
17901 +static void venc_get_timings(struct omap_dss_device *dssdev,
17902 + struct omap_video_timings *timings)
17903 +{
17904 + *timings = dssdev->panel.timings;
17905 +}
17906 +
17907 +static void venc_set_timings(struct omap_dss_device *dssdev,
17908 + struct omap_video_timings *timings)
17909 +{
17910 + DSSDBG("venc_set_timings\n");
17911 +
17912 + /* Reset WSS data when the TV standard changes. */
17913 + if (memcmp(&dssdev->panel.timings, timings, sizeof(*timings)))
17914 + venc.wss_data = 0;
17915 +
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);
17921 + }
17922 +}
17923 +
17924 +static int venc_check_timings(struct omap_dss_device *dssdev,
17925 + struct omap_video_timings *timings)
17926 +{
17927 + DSSDBG("venc_check_timings\n");
17928 +
17929 + if (memcmp(&omap_dss_pal_timings, timings, sizeof(*timings)) == 0)
17930 + return 0;
17931 +
17932 + if (memcmp(&omap_dss_ntsc_timings, timings, sizeof(*timings)) == 0)
17933 + return 0;
17934 +
17935 + return -EINVAL;
17936 +}
17937 +
17938 +static u32 venc_get_wss(struct omap_dss_device *dssdev)
17939 +{
17940 + /* Invert due to VENC_L21_WC_CTL:INV=1 */
17941 + return (venc.wss_data >> 8) ^ 0xfffff;
17942 +}
17943 +
17944 +static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss)
17945 +{
17946 + const struct venc_config *config;
17947 +
17948 + DSSDBG("venc_set_wss\n");
17949 +
17950 + mutex_lock(&venc.venc_lock);
17951 +
17952 + config = venc_timings_to_config(&dssdev->panel.timings);
17953 +
17954 + /* Invert due to VENC_L21_WC_CTL:INV=1 */
17955 + venc.wss_data = (wss ^ 0xfffff) << 8;
17956 +
17957 + venc_enable_clocks(1);
17958 +
17959 + venc_write_reg(VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data |
17960 + venc.wss_data);
17961 +
17962 + venc_enable_clocks(0);
17963 +
17964 + mutex_unlock(&venc.venc_lock);
17965 +
17966 + return 0;
17967 +}
17968 +
17969 +static enum omap_dss_update_mode venc_display_get_update_mode(
17970 + struct omap_dss_device *dssdev)
17971 +{
17972 + if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
17973 + return OMAP_DSS_UPDATE_AUTO;
17974 + else
17975 + return OMAP_DSS_UPDATE_DISABLED;
17976 +}
17977 +
17978 +int venc_init_display(struct omap_dss_device *dssdev)
17979 +{
17980 + DSSDBG("init_display\n");
17981 +
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;
17992 +
17993 + return 0;
17994 +}
17995 +
17996 +void venc_dump_regs(struct seq_file *s)
17997 +{
17998 +#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(r))
17999 +
18000 + venc_enable_clocks(1);
18001 +
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);
18043 +
18044 + venc_enable_clocks(0);
18045 +
18046 +#undef DUMPREG
18047 +}
18048 diff --git a/drivers/video/omap2/omapfb/Kconfig b/drivers/video/omap2/omapfb/Kconfig
18049 new file mode 100644
18050 index 0000000..bb694cc
18051 --- /dev/null
18052 +++ b/drivers/video/omap2/omapfb/Kconfig
18053 @@ -0,0 +1,37 @@
18054 +menuconfig FB_OMAP2
18055 + tristate "OMAP2/3 frame buffer support (EXPERIMENTAL)"
18056 + depends on FB && OMAP2_DSS
18057 +
18058 + select OMAP2_VRAM
18059 + select OMAP2_VRFB
18060 + select FB_CFB_FILLRECT
18061 + select FB_CFB_COPYAREA
18062 + select FB_CFB_IMAGEBLIT
18063 + help
18064 + Frame buffer driver for OMAP2/3 based boards.
18065 +
18066 +config FB_OMAP2_DEBUG_SUPPORT
18067 + bool "Debug support for OMAP2/3 FB"
18068 + default y
18069 + depends on FB_OMAP2
18070 + help
18071 + Support for debug output. You have to enable the actual printing
18072 + with debug module parameter.
18073 +
18074 +config FB_OMAP2_FORCE_AUTO_UPDATE
18075 + bool "Force main display to automatic update mode"
18076 + depends on FB_OMAP2
18077 + help
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
18081 + update mode.
18082 +
18083 +config FB_OMAP2_NUM_FBS
18084 + int "Number of framebuffers"
18085 + range 1 10
18086 + default 3
18087 + depends on FB_OMAP2
18088 + help
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
18094 --- /dev/null
18095 +++ b/drivers/video/omap2/omapfb/Makefile
18096 @@ -0,0 +1,2 @@
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
18102 --- /dev/null
18103 +++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c
18104 @@ -0,0 +1,727 @@
18105 +/*
18106 + * linux/drivers/video/omap2/omapfb-ioctl.c
18107 + *
18108 + * Copyright (C) 2008 Nokia Corporation
18109 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
18110 + *
18111 + * Some code and ideas taken from drivers/video/omap/ driver
18112 + * by Imre Deak.
18113 + *
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.
18117 + *
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
18121 + * more details.
18122 + *
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/>.
18125 + */
18126 +
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>
18134 +
18135 +#include <mach/display.h>
18136 +#include <mach/vrfb.h>
18137 +#include <mach/vram.h>
18138 +
18139 +#include "omapfb.h"
18140 +
18141 +static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
18142 +{
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;
18148 + int r = 0;
18149 +
18150 + DBG("omapfb_setup_plane\n");
18151 +
18152 + if (ofbi->num_overlays != 1) {
18153 + r = -EINVAL;
18154 + goto out;
18155 + }
18156 +
18157 + /* XXX uses only the first overlay */
18158 + ovl = ofbi->overlays[0];
18159 +
18160 + if (pi->enabled && !ofbi->region.size) {
18161 + /*
18162 + * This plane's memory was freed, can't enable it
18163 + * until it's reallocated.
18164 + */
18165 + r = -EINVAL;
18166 + goto out;
18167 + }
18168 +
18169 + ovl->get_overlay_info(ovl, &info);
18170 +
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;
18176 +
18177 + r = ovl->set_overlay_info(ovl, &info);
18178 + if (r)
18179 + goto out;
18180 +
18181 + if (ovl->manager) {
18182 + r = ovl->manager->apply(ovl->manager);
18183 + if (r)
18184 + goto out;
18185 + }
18186 +
18187 + if (display) {
18188 + u16 w, h;
18189 +
18190 + if (display->sync)
18191 + display->sync(display);
18192 +
18193 + display->get_resolution(display, &w, &h);
18194 +
18195 + if (display->update)
18196 + display->update(display, 0, 0, w, h);
18197 + }
18198 +
18199 +out:
18200 + if (r)
18201 + dev_err(fbdev->dev, "setup_plane failed\n");
18202 + return r;
18203 +}
18204 +
18205 +static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
18206 +{
18207 + struct omapfb_info *ofbi = FB2OFB(fbi);
18208 +
18209 + if (ofbi->num_overlays != 1) {
18210 + memset(pi, 0, sizeof(*pi));
18211 + } else {
18212 + struct omap_overlay_info *ovli;
18213 + struct omap_overlay *ovl;
18214 +
18215 + ovl = ofbi->overlays[0];
18216 + ovli = &ovl->info;
18217 +
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 */
18222 + pi->mirror = 0;
18223 + pi->out_width = ovli->out_width;
18224 + pi->out_height = ovli->out_height;
18225 + }
18226 +
18227 + return 0;
18228 +}
18229 +
18230 +static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
18231 +{
18232 + struct omapfb_info *ofbi = FB2OFB(fbi);
18233 + struct omapfb2_device *fbdev = ofbi->fbdev;
18234 + struct omapfb2_mem_region *rg;
18235 + int r, i;
18236 + size_t size;
18237 +
18238 + if (mi->type > OMAPFB_MEMTYPE_MAX)
18239 + return -EINVAL;
18240 +
18241 + size = PAGE_ALIGN(mi->size);
18242 +
18243 + rg = &ofbi->region;
18244 +
18245 + for (i = 0; i < ofbi->num_overlays; i++) {
18246 + if (ofbi->overlays[i]->info.enabled)
18247 + return -EBUSY;
18248 + }
18249 +
18250 + if (rg->size != size || rg->type != mi->type) {
18251 + r = omapfb_realloc_fbmem(fbi, size, mi->type);
18252 + if (r) {
18253 + dev_err(fbdev->dev, "realloc fbmem failed\n");
18254 + return r;
18255 + }
18256 + }
18257 +
18258 + return 0;
18259 +}
18260 +
18261 +static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
18262 +{
18263 + struct omapfb_info *ofbi = FB2OFB(fbi);
18264 + struct omapfb2_mem_region *rg;
18265 +
18266 + rg = &ofbi->region;
18267 + memset(mi, 0, sizeof(*mi));
18268 +
18269 + mi->size = rg->size;
18270 + mi->type = rg->type;
18271 +
18272 + return 0;
18273 +}
18274 +
18275 +static int omapfb_update_window(struct fb_info *fbi,
18276 + u32 x, u32 y, u32 w, u32 h)
18277 +{
18278 + struct omap_dss_device *display = fb2display(fbi);
18279 + u16 dw, dh;
18280 +
18281 + if (!display)
18282 + return 0;
18283 +
18284 + if (w == 0 || h == 0)
18285 + return 0;
18286 +
18287 + display->get_resolution(display, &dw, &dh);
18288 +
18289 + if (x + w > dw || y + h > dh)
18290 + return -EINVAL;
18291 +
18292 + display->update(display, x, y, w, h);
18293 +
18294 + return 0;
18295 +}
18296 +
18297 +static int omapfb_set_update_mode(struct fb_info *fbi,
18298 + enum omapfb_update_mode mode)
18299 +{
18300 + struct omap_dss_device *display = fb2display(fbi);
18301 + enum omap_dss_update_mode um;
18302 + int r;
18303 +
18304 + if (!display || !display->set_update_mode)
18305 + return -EINVAL;
18306 +
18307 + switch (mode) {
18308 + case OMAPFB_UPDATE_DISABLED:
18309 + um = OMAP_DSS_UPDATE_DISABLED;
18310 + break;
18311 +
18312 + case OMAPFB_AUTO_UPDATE:
18313 + um = OMAP_DSS_UPDATE_AUTO;
18314 + break;
18315 +
18316 + case OMAPFB_MANUAL_UPDATE:
18317 + um = OMAP_DSS_UPDATE_MANUAL;
18318 + break;
18319 +
18320 + default:
18321 + return -EINVAL;
18322 + }
18323 +
18324 + r = display->set_update_mode(display, um);
18325 +
18326 + return r;
18327 +}
18328 +
18329 +static int omapfb_get_update_mode(struct fb_info *fbi,
18330 + enum omapfb_update_mode *mode)
18331 +{
18332 + struct omap_dss_device *display = fb2display(fbi);
18333 + enum omap_dss_update_mode m;
18334 +
18335 + if (!display || !display->get_update_mode)
18336 + return -EINVAL;
18337 +
18338 + m = display->get_update_mode(display);
18339 +
18340 + switch (m) {
18341 + case OMAP_DSS_UPDATE_DISABLED:
18342 + *mode = OMAPFB_UPDATE_DISABLED;
18343 + break;
18344 + case OMAP_DSS_UPDATE_AUTO:
18345 + *mode = OMAPFB_AUTO_UPDATE;
18346 + break;
18347 + case OMAP_DSS_UPDATE_MANUAL:
18348 + *mode = OMAPFB_MANUAL_UPDATE;
18349 + break;
18350 + default:
18351 + BUG();
18352 + }
18353 +
18354 + return 0;
18355 +}
18356 +
18357 +/* XXX this color key handling is a hack... */
18358 +static struct omapfb_color_key omapfb_color_keys[2];
18359 +
18360 +static int _omapfb_set_color_key(struct omap_overlay_manager *mgr,
18361 + struct omapfb_color_key *ck)
18362 +{
18363 + struct omap_overlay_manager_info info;
18364 + enum omap_dss_trans_key_type kt;
18365 + int r;
18366 +
18367 + mgr->get_manager_info(mgr, &info);
18368 +
18369 + if (ck->key_type == OMAPFB_COLOR_KEY_DISABLED) {
18370 + info.trans_enabled = false;
18371 + omapfb_color_keys[mgr->id] = *ck;
18372 +
18373 + r = mgr->set_manager_info(mgr, &info);
18374 + if (r)
18375 + return r;
18376 +
18377 + r = mgr->apply(mgr);
18378 +
18379 + return r;
18380 + }
18381 +
18382 + switch (ck->key_type) {
18383 + case OMAPFB_COLOR_KEY_GFX_DST:
18384 + kt = OMAP_DSS_COLOR_KEY_GFX_DST;
18385 + break;
18386 + case OMAPFB_COLOR_KEY_VID_SRC:
18387 + kt = OMAP_DSS_COLOR_KEY_VID_SRC;
18388 + break;
18389 + default:
18390 + return -EINVAL;
18391 + }
18392 +
18393 + info.default_color = ck->background;
18394 + info.trans_key = ck->trans_key;
18395 + info.trans_key_type = kt;
18396 + info.trans_enabled = true;
18397 +
18398 + omapfb_color_keys[mgr->id] = *ck;
18399 +
18400 + r = mgr->set_manager_info(mgr, &info);
18401 + if (r)
18402 + return r;
18403 +
18404 + r = mgr->apply(mgr);
18405 +
18406 + return r;
18407 +}
18408 +
18409 +static int omapfb_set_color_key(struct fb_info *fbi,
18410 + struct omapfb_color_key *ck)
18411 +{
18412 + struct omapfb_info *ofbi = FB2OFB(fbi);
18413 + struct omapfb2_device *fbdev = ofbi->fbdev;
18414 + int r;
18415 + int i;
18416 + struct omap_overlay_manager *mgr = NULL;
18417 +
18418 + omapfb_lock(fbdev);
18419 +
18420 + for (i = 0; i < ofbi->num_overlays; i++) {
18421 + if (ofbi->overlays[i]->manager) {
18422 + mgr = ofbi->overlays[i]->manager;
18423 + break;
18424 + }
18425 + }
18426 +
18427 + if (!mgr) {
18428 + r = -EINVAL;
18429 + goto err;
18430 + }
18431 +
18432 + r = _omapfb_set_color_key(mgr, ck);
18433 +err:
18434 + omapfb_unlock(fbdev);
18435 +
18436 + return r;
18437 +}
18438 +
18439 +static int omapfb_get_color_key(struct fb_info *fbi,
18440 + struct omapfb_color_key *ck)
18441 +{
18442 + struct omapfb_info *ofbi = FB2OFB(fbi);
18443 + struct omapfb2_device *fbdev = ofbi->fbdev;
18444 + struct omap_overlay_manager *mgr = NULL;
18445 + int r = 0;
18446 + int i;
18447 +
18448 + omapfb_lock(fbdev);
18449 +
18450 + for (i = 0; i < ofbi->num_overlays; i++) {
18451 + if (ofbi->overlays[i]->manager) {
18452 + mgr = ofbi->overlays[i]->manager;
18453 + break;
18454 + }
18455 + }
18456 +
18457 + if (!mgr) {
18458 + r = -EINVAL;
18459 + goto err;
18460 + }
18461 +
18462 + *ck = omapfb_color_keys[mgr->id];
18463 +err:
18464 + omapfb_unlock(fbdev);
18465 +
18466 + return r;
18467 +}
18468 +
18469 +static int omapfb_memory_read(struct fb_info *fbi,
18470 + struct omapfb_memory_read *mr)
18471 +{
18472 + struct omap_dss_device *display = fb2display(fbi);
18473 + void *buf;
18474 + int r;
18475 +
18476 + if (!display || !display->memory_read)
18477 + return -ENOENT;
18478 +
18479 + if (!access_ok(VERIFY_WRITE, mr->buffer, mr->buffer_size))
18480 + return -EFAULT;
18481 +
18482 + if (mr->w * mr->h * 3 > mr->buffer_size)
18483 + return -EINVAL;
18484 +
18485 + buf = vmalloc(mr->buffer_size);
18486 + if (!buf) {
18487 + DBG("vmalloc failed\n");
18488 + return -ENOMEM;
18489 + }
18490 +
18491 + r = display->memory_read(display, buf, mr->buffer_size,
18492 + mr->x, mr->y, mr->w, mr->h);
18493 +
18494 + if (r > 0) {
18495 + if (copy_to_user(mr->buffer, buf, mr->buffer_size))
18496 + r = -EFAULT;
18497 + }
18498 +
18499 + vfree(buf);
18500 +
18501 + return r;
18502 +}
18503 +
18504 +static int omapfb_get_ovl_colormode(struct omapfb2_device *fbdev,
18505 + struct omapfb_ovl_colormode *mode)
18506 +{
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;
18512 + int i;
18513 +
18514 + if (ovl_idx >= fbdev->num_overlays)
18515 + return -ENODEV;
18516 + ovl = fbdev->overlays[ovl_idx];
18517 + supported_modes = ovl->supported_modes;
18518 +
18519 + mode_idx = mode->mode_idx;
18520 +
18521 + for (i = 0; i < sizeof(supported_modes) * 8; i++) {
18522 + if (!(supported_modes & (1 << i)))
18523 + continue;
18524 + /*
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.
18528 + */
18529 + if (dss_mode_to_fb_mode(1 << i, &var) < 0)
18530 + continue;
18531 +
18532 + mode_idx--;
18533 + if (mode_idx < 0)
18534 + break;
18535 + }
18536 +
18537 + if (i == sizeof(supported_modes) * 8)
18538 + return -ENOENT;
18539 +
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;
18546 +
18547 + return 0;
18548 +}
18549 +
18550 +static int omapfb_wait_for_go(struct fb_info *fbi)
18551 +{
18552 + struct omapfb_info *ofbi = FB2OFB(fbi);
18553 + int r = 0;
18554 + int i;
18555 +
18556 + for (i = 0; i < ofbi->num_overlays; ++i) {
18557 + struct omap_overlay *ovl = ofbi->overlays[i];
18558 + r = ovl->wait_for_go(ovl);
18559 + if (r)
18560 + break;
18561 + }
18562 +
18563 + return r;
18564 +}
18565 +
18566 +int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
18567 +{
18568 + struct omapfb_info *ofbi = FB2OFB(fbi);
18569 + struct omapfb2_device *fbdev = ofbi->fbdev;
18570 + struct omap_dss_device *display = fb2display(fbi);
18571 +
18572 + union {
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;
18581 + int test_num;
18582 + struct omapfb_memory_read memory_read;
18583 + struct omapfb_vram_info vram_info;
18584 + } p;
18585 +
18586 + int r = 0;
18587 +
18588 + switch (cmd) {
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 */
18593 + /*r = -EINVAL;*/
18594 + break;
18595 + }
18596 +
18597 + r = display->sync(display);
18598 + break;
18599 +
18600 + case OMAPFB_UPDATE_WINDOW_OLD:
18601 + DBG("ioctl UPDATE_WINDOW_OLD\n");
18602 + if (!display || !display->update) {
18603 + r = -EINVAL;
18604 + break;
18605 + }
18606 +
18607 + if (copy_from_user(&p.uwnd_o,
18608 + (void __user *)arg,
18609 + sizeof(p.uwnd_o))) {
18610 + r = -EFAULT;
18611 + break;
18612 + }
18613 +
18614 + r = omapfb_update_window(fbi, p.uwnd_o.x, p.uwnd_o.y,
18615 + p.uwnd_o.width, p.uwnd_o.height);
18616 + break;
18617 +
18618 + case OMAPFB_UPDATE_WINDOW:
18619 + DBG("ioctl UPDATE_WINDOW\n");
18620 + if (!display || !display->update) {
18621 + r = -EINVAL;
18622 + break;
18623 + }
18624 +
18625 + if (copy_from_user(&p.uwnd, (void __user *)arg,
18626 + sizeof(p.uwnd))) {
18627 + r = -EFAULT;
18628 + break;
18629 + }
18630 +
18631 + r = omapfb_update_window(fbi, p.uwnd.x, p.uwnd.y,
18632 + p.uwnd.width, p.uwnd.height);
18633 + break;
18634 +
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)))
18639 + r = -EFAULT;
18640 + else
18641 + r = omapfb_setup_plane(fbi, &p.plane_info);
18642 + break;
18643 +
18644 + case OMAPFB_QUERY_PLANE:
18645 + DBG("ioctl QUERY_PLANE\n");
18646 + r = omapfb_query_plane(fbi, &p.plane_info);
18647 + if (r < 0)
18648 + break;
18649 + if (copy_to_user((void __user *)arg, &p.plane_info,
18650 + sizeof(p.plane_info)))
18651 + r = -EFAULT;
18652 + break;
18653 +
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)))
18658 + r = -EFAULT;
18659 + else
18660 + r = omapfb_setup_mem(fbi, &p.mem_info);
18661 + break;
18662 +
18663 + case OMAPFB_QUERY_MEM:
18664 + DBG("ioctl QUERY_MEM\n");
18665 + r = omapfb_query_mem(fbi, &p.mem_info);
18666 + if (r < 0)
18667 + break;
18668 + if (copy_to_user((void __user *)arg, &p.mem_info,
18669 + sizeof(p.mem_info)))
18670 + r = -EFAULT;
18671 + break;
18672 +
18673 + case OMAPFB_GET_CAPS:
18674 + DBG("ioctl GET_CAPS\n");
18675 + if (!display) {
18676 + r = -EINVAL;
18677 + break;
18678 + }
18679 +
18680 + memset(&p.caps, 0, sizeof(p.caps));
18681 + p.caps.ctrl = display->caps;
18682 +
18683 + if (copy_to_user((void __user *)arg, &p.caps, sizeof(p.caps)))
18684 + r = -EFAULT;
18685 + break;
18686 +
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))) {
18691 + r = -EFAULT;
18692 + break;
18693 + }
18694 + r = omapfb_get_ovl_colormode(fbdev, &p.ovl_colormode);
18695 + if (r < 0)
18696 + break;
18697 + if (copy_to_user((void __user *)arg, &p.ovl_colormode,
18698 + sizeof(p.ovl_colormode)))
18699 + r = -EFAULT;
18700 + break;
18701 +
18702 + case OMAPFB_SET_UPDATE_MODE:
18703 + DBG("ioctl SET_UPDATE_MODE\n");
18704 + if (get_user(p.update_mode, (int __user *)arg))
18705 + r = -EFAULT;
18706 + else
18707 + r = omapfb_set_update_mode(fbi, p.update_mode);
18708 + break;
18709 +
18710 + case OMAPFB_GET_UPDATE_MODE:
18711 + DBG("ioctl GET_UPDATE_MODE\n");
18712 + r = omapfb_get_update_mode(fbi, &p.update_mode);
18713 + if (r)
18714 + break;
18715 + if (put_user(p.update_mode,
18716 + (enum omapfb_update_mode __user *)arg))
18717 + r = -EFAULT;
18718 + break;
18719 +
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)))
18724 + r = -EFAULT;
18725 + else
18726 + r = omapfb_set_color_key(fbi, &p.color_key);
18727 + break;
18728 +
18729 + case OMAPFB_GET_COLOR_KEY:
18730 + DBG("ioctl GET_COLOR_KEY\n");
18731 + r = omapfb_get_color_key(fbi, &p.color_key);
18732 + if (r)
18733 + break;
18734 + if (copy_to_user((void __user *)arg, &p.color_key,
18735 + sizeof(p.color_key)))
18736 + r = -EFAULT;
18737 + break;
18738 +
18739 + case OMAPFB_WAITFORVSYNC:
18740 + DBG("ioctl WAITFORVSYNC\n");
18741 + if (!display) {
18742 + r = -EINVAL;
18743 + break;
18744 + }
18745 +
18746 + r = display->wait_vsync(display);
18747 + break;
18748 +
18749 + case OMAPFB_WAITFORGO:
18750 + DBG("ioctl WAITFORGO\n");
18751 + if (!display) {
18752 + r = -EINVAL;
18753 + break;
18754 + }
18755 +
18756 + r = omapfb_wait_for_go(fbi);
18757 + break;
18758 +
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)) {
18764 + r = -EFAULT;
18765 + break;
18766 + }
18767 + if (!display || !display->run_test) {
18768 + r = -EINVAL;
18769 + break;
18770 + }
18771 +
18772 + r = display->run_test(display, p.test_num);
18773 +
18774 + break;
18775 +
18776 + case OMAPFB_CTRL_TEST:
18777 + DBG("ioctl CTRL_TEST\n");
18778 + if (get_user(p.test_num, (int __user *)arg)) {
18779 + r = -EFAULT;
18780 + break;
18781 + }
18782 + if (!display || !display->run_test) {
18783 + r = -EINVAL;
18784 + break;
18785 + }
18786 +
18787 + r = display->run_test(display, p.test_num);
18788 +
18789 + break;
18790 +
18791 + case OMAPFB_MEMORY_READ:
18792 + DBG("ioctl MEMORY_READ\n");
18793 +
18794 + if (copy_from_user(&p.memory_read, (void __user *)arg,
18795 + sizeof(p.memory_read))) {
18796 + r = -EFAULT;
18797 + break;
18798 + }
18799 +
18800 + r = omapfb_memory_read(fbi, &p.memory_read);
18801 +
18802 + break;
18803 +
18804 + case OMAPFB_GET_VRAM_INFO: {
18805 + unsigned long vram, free, largest;
18806 +
18807 + DBG("ioctl GET_VRAM_INFO\n");
18808 +
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;
18813 +
18814 + if (copy_to_user((void __user *)arg, &p.vram_info,
18815 + sizeof(p.vram_info)))
18816 + r = -EFAULT;
18817 + break;
18818 + }
18819 +
18820 + default:
18821 + dev_err(fbdev->dev, "Unknown ioctl 0x%x\n", cmd);
18822 + r = -EINVAL;
18823 + }
18824 +
18825 + if (r < 0)
18826 + DBG("ioctl failed: %d\n", r);
18827 +
18828 + return r;
18829 +}
18830 +
18831 +
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
18835 --- /dev/null
18836 +++ b/drivers/video/omap2/omapfb/omapfb-main.c
18837 @@ -0,0 +1,2137 @@
18838 +/*
18839 + * linux/drivers/video/omap2/omapfb-main.c
18840 + *
18841 + * Copyright (C) 2008 Nokia Corporation
18842 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
18843 + *
18844 + * Some code and ideas taken from drivers/video/omap/ driver
18845 + * by Imre Deak.
18846 + *
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.
18850 + *
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
18854 + * more details.
18855 + *
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/>.
18858 + */
18859 +
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>
18868 +
18869 +#include <mach/display.h>
18870 +#include <mach/vram.h>
18871 +#include <mach/vrfb.h>
18872 +
18873 +#include "omapfb.h"
18874 +
18875 +#define MODULE_NAME "omapfb"
18876 +
18877 +#define OMAPFB_PLANE_XRES_MIN 8
18878 +#define OMAPFB_PLANE_YRES_MIN 8
18879 +
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;
18885 +
18886 +#ifdef DEBUG
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);
18891 +#endif
18892 +
18893 +static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi);
18894 +
18895 +#ifdef DEBUG
18896 +static void draw_pixel(struct fb_info *fbi, int x, int y, unsigned color)
18897 +{
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;
18903 +
18904 + int r = (color >> 16) & 0xff;
18905 + int g = (color >> 8) & 0xff;
18906 + int b = (color >> 0) & 0xff;
18907 +
18908 + if (var->bits_per_pixel == 16) {
18909 + u16 __iomem *p = (u16 __iomem *)addr;
18910 + p += y * line_len + x;
18911 +
18912 + r = r * 32 / 256;
18913 + g = g * 64 / 256;
18914 + b = b * 32 / 256;
18915 +
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;
18920 +
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);
18928 + }
18929 +}
18930 +
18931 +static void fill_fb(struct fb_info *fbi)
18932 +{
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;
18937 + int y, x;
18938 +
18939 + if (!addr)
18940 + return;
18941 +
18942 + DBG("fill_fb %dx%d, line_len %d bytes\n", w, h, fbi->fix.line_length);
18943 +
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;
18966 + unsigned c;
18967 + if (var->bits_per_pixel == 16) {
18968 + if (t == 0)
18969 + b = (y % 32) * 256 / 32;
18970 + else if (t == 1)
18971 + g = (y % 64) * 256 / 64;
18972 + else if (t == 2)
18973 + r = (y % 32) * 256 / 32;
18974 + } else {
18975 + if (t == 0)
18976 + b = (y % 256);
18977 + else if (t == 1)
18978 + g = (y % 256);
18979 + else if (t == 2)
18980 + r = (y % 256);
18981 + }
18982 + c = (r << 16) | (g << 8) | (b << 0);
18983 + draw_pixel(fbi, x, y, c);
18984 + } else {
18985 + draw_pixel(fbi, x, y, 0);
18986 + }
18987 + }
18988 + }
18989 +}
18990 +#endif
18991 +
18992 +static unsigned omapfb_get_vrfb_offset(struct omapfb_info *ofbi, int rot)
18993 +{
18994 + struct vrfb *vrfb = &ofbi->region.vrfb;
18995 + unsigned offset;
18996 +
18997 + switch (rot) {
18998 + case FB_ROTATE_UR:
18999 + offset = 0;
19000 + break;
19001 + case FB_ROTATE_CW:
19002 + offset = vrfb->yoffset;
19003 + break;
19004 + case FB_ROTATE_UD:
19005 + offset = vrfb->yoffset * OMAP_VRFB_LINE_LEN + vrfb->xoffset;
19006 + break;
19007 + case FB_ROTATE_CCW:
19008 + offset = vrfb->xoffset * OMAP_VRFB_LINE_LEN;
19009 + break;
19010 + default:
19011 + BUG();
19012 + }
19013 +
19014 + offset *= vrfb->bytespp;
19015 +
19016 + return offset;
19017 +}
19018 +
19019 +static u32 omapfb_get_region_rot_paddr(struct omapfb_info *ofbi, int rot)
19020 +{
19021 + if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
19022 + return ofbi->region.vrfb.paddr[rot]
19023 + + omapfb_get_vrfb_offset(ofbi, rot);
19024 + } else {
19025 + return ofbi->region.paddr;
19026 + }
19027 +}
19028 +
19029 +static u32 omapfb_get_region_paddr(struct omapfb_info *ofbi)
19030 +{
19031 + if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
19032 + return ofbi->region.vrfb.paddr[0];
19033 + else
19034 + return ofbi->region.paddr;
19035 +}
19036 +
19037 +static void __iomem *omapfb_get_region_vaddr(struct omapfb_info *ofbi)
19038 +{
19039 + if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
19040 + return ofbi->region.vrfb.vaddr[0];
19041 + else
19042 + return ofbi->region.vaddr;
19043 +}
19044 +
19045 +static struct omapfb_colormode omapfb_colormodes[] = {
19046 + {
19047 + .dssmode = OMAP_DSS_COLOR_UYVY,
19048 + .bits_per_pixel = 16,
19049 + .nonstd = OMAPFB_COLOR_YUV422,
19050 + }, {
19051 + .dssmode = OMAP_DSS_COLOR_YUV2,
19052 + .bits_per_pixel = 16,
19053 + .nonstd = OMAPFB_COLOR_YUY422,
19054 + }, {
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 },
19061 + }, {
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 },
19068 + }, {
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 },
19075 + }, {
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 },
19082 + }, {
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 },
19089 + }, {
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 },
19096 + }, {
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 },
19103 + },
19104 +};
19105 +
19106 +static bool cmp_var_to_colormode(struct fb_var_screeninfo *var,
19107 + struct omapfb_colormode *color)
19108 +{
19109 + bool cmp_component(struct fb_bitfield *f1, struct fb_bitfield *f2)
19110 + {
19111 + return f1->length == f2->length &&
19112 + f1->offset == f2->offset &&
19113 + f1->msb_right == f2->msb_right;
19114 + }
19115 +
19116 + if (var->bits_per_pixel == 0 ||
19117 + var->red.length == 0 ||
19118 + var->blue.length == 0 ||
19119 + var->green.length == 0)
19120 + return 0;
19121 +
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);
19127 +}
19128 +
19129 +static void assign_colormode_to_var(struct fb_var_screeninfo *var,
19130 + struct omapfb_colormode *color)
19131 +{
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;
19138 +}
19139 +
19140 +static enum omap_color_mode fb_mode_to_dss_mode(struct fb_var_screeninfo *var)
19141 +{
19142 + enum omap_color_mode dssmode;
19143 + int i;
19144 +
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;
19152 + }
19153 + }
19154 +
19155 + return -EINVAL;
19156 + }
19157 +
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;
19164 + }
19165 + }
19166 +
19167 + /* match with bpp if user has not filled color fields
19168 + * properly */
19169 + switch (var->bits_per_pixel) {
19170 + case 1:
19171 + dssmode = OMAP_DSS_COLOR_CLUT1;
19172 + break;
19173 + case 2:
19174 + dssmode = OMAP_DSS_COLOR_CLUT2;
19175 + break;
19176 + case 4:
19177 + dssmode = OMAP_DSS_COLOR_CLUT4;
19178 + break;
19179 + case 8:
19180 + dssmode = OMAP_DSS_COLOR_CLUT8;
19181 + break;
19182 + case 12:
19183 + dssmode = OMAP_DSS_COLOR_RGB12U;
19184 + break;
19185 + case 16:
19186 + dssmode = OMAP_DSS_COLOR_RGB16;
19187 + break;
19188 + case 24:
19189 + dssmode = OMAP_DSS_COLOR_RGB24P;
19190 + break;
19191 + case 32:
19192 + dssmode = OMAP_DSS_COLOR_RGB24U;
19193 + break;
19194 + default:
19195 + return -EINVAL;
19196 + }
19197 +
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;
19203 + }
19204 + }
19205 +
19206 + return -EINVAL;
19207 +}
19208 +
19209 +int dss_mode_to_fb_mode(enum omap_color_mode dssmode,
19210 + struct fb_var_screeninfo *var)
19211 +{
19212 + int i;
19213 +
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);
19218 + return 0;
19219 + }
19220 + }
19221 + return -ENOENT;
19222 +}
19223 +
19224 +void set_fb_fix(struct fb_info *fbi)
19225 +{
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;
19230 +
19231 + DBG("set_fb_fix\n");
19232 +
19233 + /* used by open/write in fbmem.c */
19234 + fbi->screen_base = (char __iomem *)omapfb_get_region_vaddr(ofbi);
19235 +
19236 + DBG("changing rotation to %d\n", var->rotate);
19237 +
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;
19245 + break;
19246 + default:
19247 + fix->line_length =
19248 + (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 3;
19249 + break;
19250 + }
19251 + } else
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;
19256 +
19257 + fix->type = FB_TYPE_PACKED_PIXELS;
19258 +
19259 + if (var->nonstd)
19260 + fix->visual = FB_VISUAL_PSEUDOCOLOR;
19261 + else {
19262 + switch (var->bits_per_pixel) {
19263 + case 32:
19264 + case 24:
19265 + case 16:
19266 + case 12:
19267 + fix->visual = FB_VISUAL_TRUECOLOR;
19268 + /* 12bpp is stored in 16 bits */
19269 + break;
19270 + case 1:
19271 + case 2:
19272 + case 4:
19273 + case 8:
19274 + fix->visual = FB_VISUAL_PSEUDOCOLOR;
19275 + break;
19276 + }
19277 + }
19278 +
19279 + fix->accel = FB_ACCEL_NONE;
19280 +
19281 + fix->xpanstep = 1;
19282 + fix->ypanstep = 1;
19283 +
19284 + if (rg->size && ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
19285 + unsigned bytespp;
19286 + bool yuv_mode;
19287 + enum omap_color_mode mode;
19288 +
19289 + mode = fb_mode_to_dss_mode(var);
19290 +
19291 + bytespp = var->bits_per_pixel >> 3;
19292 +
19293 + if (mode == OMAP_DSS_COLOR_YUV2 || mode == OMAP_DSS_COLOR_UYVY)
19294 + yuv_mode = true;
19295 + else
19296 + yuv_mode = false;
19297 +
19298 + omap_vrfb_setup(&rg->vrfb, rg->paddr,
19299 + var->xres_virtual,
19300 + var->yres_virtual,
19301 + bytespp, yuv_mode);
19302 + }
19303 +}
19304 +
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)
19307 +{
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;
19315 + int i;
19316 + int bytespp;
19317 +
19318 + DBG("check_fb_var %d\n", ofbi->id);
19319 +
19320 + if (ofbi->region.size == 0)
19321 + return 0;
19322 +
19323 + mode = fb_mode_to_dss_mode(var);
19324 + if (mode < 0) {
19325 + DBG("cannot convert var to omap dss mode\n");
19326 + return -EINVAL;
19327 + }
19328 +
19329 + for (i = 0; i < ofbi->num_overlays; ++i) {
19330 + if ((ofbi->overlays[i]->supported_modes & mode) == 0) {
19331 + DBG("invalid mode\n");
19332 + return -EINVAL;
19333 + }
19334 + }
19335 +
19336 + if (var->rotate < 0 || var->rotate > 3)
19337 + return -EINVAL;
19338 +
19339 + xres_min = OMAPFB_PLANE_XRES_MIN;
19340 + xres_max = 2048;
19341 + yres_min = OMAPFB_PLANE_YRES_MIN;
19342 + yres_max = 2048;
19343 +
19344 + bytespp = var->bits_per_pixel >> 3;
19345 +
19346 + /* XXX: some applications seem to set virtual res to 0. */
19347 + if (var->xres_virtual == 0)
19348 + var->xres_virtual = var->xres;
19349 +
19350 + if (var->yres_virtual == 0)
19351 + var->yres_virtual = var->yres;
19352 +
19353 + if (var->xres_virtual < xres_min || var->yres_virtual < yres_min)
19354 + return -EINVAL;
19355 +
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;
19364 +
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;
19369 +
19370 + if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
19371 + line_size = OMAP_VRFB_LINE_LEN * bytespp;
19372 + else
19373 + line_size = var->xres_virtual * bytespp;
19374 +
19375 + max_frame_size = ofbi->region.size;
19376 +
19377 + DBG("max frame size %lu, line size %lu\n", max_frame_size, line_size);
19378 +
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;
19382 +
19383 + if (var->yres_virtual < yres_min)
19384 + var->yres_virtual = yres_min;
19385 +
19386 + if (var->yres > var->yres_virtual)
19387 + var->yres = var->yres_virtual;
19388 + }
19389 +
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)
19393 + return -EINVAL;
19394 +
19395 + var->xres_virtual = max_frame_size / var->yres_virtual /
19396 + bytespp;
19397 +
19398 + if (var->xres_virtual < xres_min)
19399 + var->xres_virtual = xres_min;
19400 +
19401 + if (var->xres > var->xres_virtual)
19402 + var->xres = var->xres_virtual;
19403 +
19404 + line_size = var->xres_virtual * bytespp;
19405 + }
19406 +
19407 + if (line_size * var->yres_virtual > max_frame_size) {
19408 + DBG("cannot fit FB to memory\n");
19409 + return -EINVAL;
19410 + }
19411 +
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;
19416 +
19417 + DBG("xres = %d, yres = %d, vxres = %d, vyres = %d\n",
19418 + var->xres, var->yres,
19419 + var->xres_virtual, var->yres_virtual);
19420 +
19421 + var->height = -1;
19422 + var->width = -1;
19423 + var->grayscale = 0;
19424 +
19425 + if (display && display->get_timings) {
19426 + struct omap_video_timings timings;
19427 + display->get_timings(display, &timings);
19428 +
19429 + /* pixclock in ps, the rest in pixclock */
19430 + var->pixclock = timings.pixel_clock != 0 ?
19431 + KHZ2PICOS(timings.pixel_clock) :
19432 + 0;
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;
19439 + } else {
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;
19447 + }
19448 +
19449 + /* TODO: get these from panel->config */
19450 + var->vmode = FB_VMODE_NONINTERLACED;
19451 + var->sync = 0;
19452 +
19453 + return 0;
19454 +}
19455 +
19456 +/*
19457 + * ---------------------------------------------------------------------------
19458 + * fbdev framework callbacks
19459 + * ---------------------------------------------------------------------------
19460 + */
19461 +static int omapfb_open(struct fb_info *fbi, int user)
19462 +{
19463 + return 0;
19464 +}
19465 +
19466 +static int omapfb_release(struct fb_info *fbi, int user)
19467 +{
19468 +#if 0
19469 + struct omapfb_info *ofbi = FB2OFB(fbi);
19470 + struct omapfb2_device *fbdev = ofbi->fbdev;
19471 + struct omap_dss_device *display = fb2display(fbi);
19472 +
19473 + DBG("Closing fb with plane index %d\n", ofbi->id);
19474 +
19475 + omapfb_lock(fbdev);
19476 +
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) {
19482 + u16 w, h;
19483 +
19484 + if (display->sync)
19485 + display->sync(display);
19486 +
19487 + display->get_resolution(display, &w, &h);
19488 + display->update(display, 0, 0, w, h);
19489 + }
19490 + }
19491 +
19492 + if (display && display->sync)
19493 + display->sync(display);
19494 +
19495 + omapfb_unlock(fbdev);
19496 +#endif
19497 + return 0;
19498 +}
19499 +
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)
19503 +{
19504 + int r = 0;
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;
19509 + int offset;
19510 + u32 data_start_p;
19511 + void __iomem *data_start_v;
19512 + struct omap_overlay_info info;
19513 + int xres, yres;
19514 + int screen_width;
19515 + int mirror;
19516 + int rotation = var->rotate;
19517 + int i;
19518 +
19519 + for (i = 0; i < ofbi->num_overlays; i++) {
19520 + if (ovl != ofbi->overlays[i])
19521 + continue;
19522 +
19523 + rotation = (rotation + ofbi->rotation[i]) % 4;
19524 + break;
19525 + }
19526 +
19527 + DBG("setup_overlay %d, posx %d, posy %d, outw %d, outh %d\n", ofbi->id,
19528 + posx, posy, outw, outh);
19529 +
19530 + if (rotation == FB_ROTATE_CW || rotation == FB_ROTATE_CCW) {
19531 + xres = var->yres;
19532 + yres = var->xres;
19533 + } else {
19534 + xres = var->xres;
19535 + yres = var->yres;
19536 + }
19537 +
19538 + offset = ((var->yoffset * var->xres_virtual +
19539 + var->xoffset) * var->bits_per_pixel) >> 3;
19540 +
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;
19544 + } else {
19545 + data_start_p = omapfb_get_region_paddr(ofbi);
19546 + data_start_v = omapfb_get_region_vaddr(ofbi);
19547 + }
19548 +
19549 + data_start_p += offset;
19550 + data_start_v += offset;
19551 +
19552 + mode = fb_mode_to_dss_mode(var);
19553 +
19554 + if (mode == -EINVAL) {
19555 + DBG("fb_mode_to_dss_mode failed");
19556 + r = -EINVAL;
19557 + goto err;
19558 + }
19559 +
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);
19566 + break;
19567 + }
19568 + default:
19569 + screen_width = fix->line_length / (var->bits_per_pixel >> 3);
19570 + break;
19571 + }
19572 +
19573 + ovl->get_overlay_info(ovl, &info);
19574 +
19575 + if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
19576 + mirror = 0;
19577 + else
19578 + mirror = ofbi->mirror;
19579 +
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;
19589 +
19590 + info.pos_x = posx;
19591 + info.pos_y = posy;
19592 + info.out_width = outw;
19593 + info.out_height = outh;
19594 +
19595 + r = ovl->set_overlay_info(ovl, &info);
19596 + if (r) {
19597 + DBG("ovl->setup_overlay_info failed\n");
19598 + goto err;
19599 + }
19600 +
19601 + return 0;
19602 +
19603 +err:
19604 + DBG("setup_overlay failed\n");
19605 + return r;
19606 +}
19607 +
19608 +/* apply var to the overlay */
19609 +int omapfb_apply_changes(struct fb_info *fbi, int init)
19610 +{
19611 + int r = 0;
19612 + struct omapfb_info *ofbi = FB2OFB(fbi);
19613 + struct fb_var_screeninfo *var = &fbi->var;
19614 + struct omap_overlay *ovl;
19615 + u16 posx, posy;
19616 + u16 outw, outh;
19617 + int i;
19618 +
19619 +#ifdef DEBUG
19620 + if (omapfb_test_pattern)
19621 + fill_fb(fbi);
19622 +#endif
19623 +
19624 + for (i = 0; i < ofbi->num_overlays; i++) {
19625 + ovl = ofbi->overlays[i];
19626 +
19627 + DBG("apply_changes, fb %d, ovl %d\n", ofbi->id, ovl->id);
19628 +
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);
19634 + continue;
19635 + }
19636 +
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;
19643 + } else {
19644 + outw = var->xres;
19645 + outh = var->yres;
19646 + }
19647 + } else {
19648 + outw = ovl->info.out_width;
19649 + outh = ovl->info.out_height;
19650 + }
19651 +
19652 + if (init) {
19653 + posx = 0;
19654 + posy = 0;
19655 + } else {
19656 + posx = ovl->info.pos_x;
19657 + posy = ovl->info.pos_y;
19658 + }
19659 +
19660 + r = omapfb_setup_overlay(fbi, ovl, posx, posy, outw, outh);
19661 + if (r)
19662 + goto err;
19663 +
19664 + if (!init && ovl->manager)
19665 + ovl->manager->apply(ovl->manager);
19666 + }
19667 + return 0;
19668 +err:
19669 + DBG("apply_changes failed\n");
19670 + return r;
19671 +}
19672 +
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)
19676 +{
19677 + int r;
19678 +
19679 + DBG("check_var(%d)\n", FB2OFB(fbi)->id);
19680 +
19681 + r = check_fb_var(fbi, var);
19682 +
19683 + return r;
19684 +}
19685 +
19686 +/* set the video mode according to info->var */
19687 +static int omapfb_set_par(struct fb_info *fbi)
19688 +{
19689 + int r;
19690 +
19691 + DBG("set_par(%d)\n", FB2OFB(fbi)->id);
19692 +
19693 + set_fb_fix(fbi);
19694 + r = omapfb_apply_changes(fbi, 0);
19695 +
19696 + return r;
19697 +}
19698 +
19699 +static int omapfb_pan_display(struct fb_var_screeninfo *var,
19700 + struct fb_info *fbi)
19701 +{
19702 + struct omapfb_info *ofbi = FB2OFB(fbi);
19703 + int r = 0;
19704 +
19705 + DBG("pan_display(%d)\n", ofbi->id);
19706 +
19707 + if (var->xoffset != fbi->var.xoffset ||
19708 + var->yoffset != fbi->var.yoffset) {
19709 + struct fb_var_screeninfo new_var;
19710 +
19711 + new_var = fbi->var;
19712 + new_var.xoffset = var->xoffset;
19713 + new_var.yoffset = var->yoffset;
19714 +
19715 + r = check_fb_var(fbi, &new_var);
19716 +
19717 + if (r == 0) {
19718 + fbi->var = new_var;
19719 + set_fb_fix(fbi);
19720 + r = omapfb_apply_changes(fbi, 0);
19721 + }
19722 + }
19723 +
19724 + return r;
19725 +}
19726 +
19727 +static void mmap_user_open(struct vm_area_struct *vma)
19728 +{
19729 + struct omapfb_info *ofbi = (struct omapfb_info *)vma->vm_private_data;
19730 +
19731 + atomic_inc(&ofbi->map_count);
19732 +}
19733 +
19734 +static void mmap_user_close(struct vm_area_struct *vma)
19735 +{
19736 + struct omapfb_info *ofbi = (struct omapfb_info *)vma->vm_private_data;
19737 +
19738 + atomic_dec(&ofbi->map_count);
19739 +}
19740 +
19741 +static struct vm_operations_struct mmap_user_ops = {
19742 + .open = mmap_user_open,
19743 + .close = mmap_user_close,
19744 +};
19745 +
19746 +static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
19747 +{
19748 + struct omapfb_info *ofbi = FB2OFB(fbi);
19749 + struct fb_fix_screeninfo *fix = &fbi->fix;
19750 + unsigned long off;
19751 + unsigned long start;
19752 + u32 len;
19753 +
19754 + if (vma->vm_end - vma->vm_start == 0)
19755 + return 0;
19756 + if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
19757 + return -EINVAL;
19758 + off = vma->vm_pgoff << PAGE_SHIFT;
19759 +
19760 + start = omapfb_get_region_paddr(ofbi);
19761 + len = fix->smem_len;
19762 + if (off >= len)
19763 + return -EINVAL;
19764 + if ((vma->vm_end - vma->vm_start + off) > len)
19765 + return -EINVAL;
19766 +
19767 + off += start;
19768 +
19769 + DBG("user mmap region start %lx, len %d, off %lx\n", start, len, off);
19770 +
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))
19778 + return -EAGAIN;
19779 + /* vm_ops.open won't be called for mmap itself. */
19780 + atomic_inc(&ofbi->map_count);
19781 + return 0;
19782 +}
19783 +
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.
19787 + */
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)
19790 +{
19791 + /*struct omapfb_info *ofbi = FB2OFB(fbi);*/
19792 + /*struct omapfb2_device *fbdev = ofbi->fbdev;*/
19793 + struct fb_var_screeninfo *var = &fbi->var;
19794 + int r = 0;
19795 +
19796 + enum omapfb_color_format mode = OMAPFB_COLOR_RGB24U; /* XXX */
19797 +
19798 + /*switch (plane->color_mode) {*/
19799 + switch (mode) {
19800 + case OMAPFB_COLOR_YUV422:
19801 + case OMAPFB_COLOR_YUV420:
19802 + case OMAPFB_COLOR_YUY422:
19803 + r = -EINVAL;
19804 + break;
19805 + case OMAPFB_COLOR_CLUT_8BPP:
19806 + case OMAPFB_COLOR_CLUT_4BPP:
19807 + case OMAPFB_COLOR_CLUT_2BPP:
19808 + case OMAPFB_COLOR_CLUT_1BPP:
19809 + /*
19810 + if (fbdev->ctrl->setcolreg)
19811 + r = fbdev->ctrl->setcolreg(regno, red, green, blue,
19812 + transp, update_hw_pal);
19813 + */
19814 + /* Fallthrough */
19815 + r = -EINVAL;
19816 + break;
19817 + case OMAPFB_COLOR_RGB565:
19818 + case OMAPFB_COLOR_RGB444:
19819 + case OMAPFB_COLOR_RGB24P:
19820 + case OMAPFB_COLOR_RGB24U:
19821 + if (r != 0)
19822 + break;
19823 +
19824 + if (regno < 0) {
19825 + r = -EINVAL;
19826 + break;
19827 + }
19828 +
19829 + if (regno < 16) {
19830 + u16 pal;
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;
19837 + }
19838 + break;
19839 + default:
19840 + BUG();
19841 + }
19842 + return r;
19843 +}
19844 +
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)
19847 +{
19848 + DBG("setcolreg\n");
19849 +
19850 + return _setcolreg(info, regno, red, green, blue, transp, 1);
19851 +}
19852 +
19853 +static int omapfb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
19854 +{
19855 + int count, index, r;
19856 + u16 *red, *green, *blue, *transp;
19857 + u16 trans = 0xffff;
19858 +
19859 + DBG("setcmap\n");
19860 +
19861 + red = cmap->red;
19862 + green = cmap->green;
19863 + blue = cmap->blue;
19864 + transp = cmap->transp;
19865 + index = cmap->start;
19866 +
19867 + for (count = 0; count < cmap->len; count++) {
19868 + if (transp)
19869 + trans = *transp++;
19870 + r = _setcolreg(info, index++, *red++, *green++, *blue++, trans,
19871 + count == cmap->len - 1);
19872 + if (r != 0)
19873 + return r;
19874 + }
19875 +
19876 + return 0;
19877 +}
19878 +
19879 +static void omapfb_vrfb_suspend_all(struct omapfb2_device *fbdev)
19880 +{
19881 + int i;
19882 +
19883 + for (i = 0; i < fbdev->num_fbs; i++) {
19884 + struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
19885 +
19886 + if (ofbi->region.vrfb.vaddr[0])
19887 + omap_vrfb_suspend_ctx(&ofbi->region.vrfb);
19888 + }
19889 +}
19890 +
19891 +static void omapfb_vrfb_resume_all(struct omapfb2_device *fbdev)
19892 +{
19893 + int i;
19894 +
19895 + for (i = 0; i < fbdev->num_fbs; i++) {
19896 + struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
19897 +
19898 + if (ofbi->region.vrfb.vaddr[0])
19899 + omap_vrfb_resume_ctx(&ofbi->region.vrfb);
19900 + }
19901 +}
19902 +
19903 +static int omapfb_blank(int blank, struct fb_info *fbi)
19904 +{
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;
19909 + int r = 0;
19910 +
19911 + omapfb_lock(fbdev);
19912 +
19913 + switch (blank) {
19914 + case FB_BLANK_UNBLANK:
19915 + if (display->state != OMAP_DSS_DISPLAY_SUSPENDED)
19916 + goto exit;
19917 +
19918 + omapfb_vrfb_resume_all(fbdev);
19919 +
19920 + if (display->resume)
19921 + r = display->resume(display);
19922 +
19923 + if (r == 0 && display->get_update_mode &&
19924 + display->get_update_mode(display) ==
19925 + OMAP_DSS_UPDATE_MANUAL)
19926 + do_update = 1;
19927 +
19928 + break;
19929 +
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)
19937 + goto exit;
19938 +
19939 + if (display->suspend)
19940 + r = display->suspend(display);
19941 +
19942 + omapfb_vrfb_suspend_all(fbdev);
19943 +
19944 + break;
19945 +
19946 + default:
19947 + r = -EINVAL;
19948 + }
19949 +
19950 +exit:
19951 + omapfb_unlock(fbdev);
19952 +
19953 + if (r == 0 && do_update && display->update) {
19954 + u16 w, h;
19955 + display->get_resolution(display, &w, &h);
19956 +
19957 + r = display->update(display, 0, 0, w, h);
19958 + }
19959 +
19960 + return r;
19961 +}
19962 +
19963 +#if 0
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)
19967 +{
19968 + DBG("omapfb_write %d, %lu\n", count, (unsigned long)*ppos);
19969 + /* XXX needed for VRFB */
19970 + return count;
19971 +}
19972 +#endif
19973 +
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,*/
19990 +};
19991 +
19992 +static void omapfb_free_fbmem(struct fb_info *fbi)
19993 +{
19994 + struct omapfb_info *ofbi = FB2OFB(fbi);
19995 + struct omapfb2_device *fbdev = ofbi->fbdev;
19996 + struct omapfb2_mem_region *rg;
19997 +
19998 + rg = &ofbi->region;
19999 +
20000 + if (rg->paddr)
20001 + if (omap_vram_free(rg->paddr, rg->size))
20002 + dev_err(fbdev->dev, "VRAM FREE failed\n");
20003 +
20004 + if (rg->vaddr)
20005 + iounmap(rg->vaddr);
20006 +
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);
20012 + }
20013 + }
20014 +
20015 + rg->vaddr = NULL;
20016 + rg->paddr = 0;
20017 + rg->alloc = 0;
20018 + rg->size = 0;
20019 +}
20020 +
20021 +static void clear_fb_info(struct fb_info *fbi)
20022 +{
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));
20026 +}
20027 +
20028 +static int omapfb_free_all_fbmem(struct omapfb2_device *fbdev)
20029 +{
20030 + int i;
20031 +
20032 + DBG("free all fbmem\n");
20033 +
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);
20038 + }
20039 +
20040 + return 0;
20041 +}
20042 +
20043 +static int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size,
20044 + unsigned long paddr)
20045 +{
20046 + struct omapfb_info *ofbi = FB2OFB(fbi);
20047 + struct omapfb2_device *fbdev = ofbi->fbdev;
20048 + struct omapfb2_mem_region *rg;
20049 + void __iomem *vaddr;
20050 + int r;
20051 +
20052 + rg = &ofbi->region;
20053 + memset(rg, 0, sizeof(*rg));
20054 +
20055 + size = PAGE_ALIGN(size);
20056 +
20057 + if (!paddr) {
20058 + DBG("allocating %lu bytes for fb %d\n", size, ofbi->id);
20059 + r = omap_vram_alloc(OMAP_VRAM_MEMTYPE_SDRAM, size, &paddr);
20060 + } else {
20061 + DBG("reserving %lu bytes at %lx for fb %d\n", size, paddr,
20062 + ofbi->id);
20063 + r = omap_vram_reserve(paddr, size);
20064 + }
20065 +
20066 + if (r) {
20067 + dev_err(fbdev->dev, "failed to allocate framebuffer\n");
20068 + return -ENOMEM;
20069 + }
20070 +
20071 + if (ofbi->rotation_type != OMAP_DSS_ROT_VRFB) {
20072 + vaddr = ioremap_wc(paddr, size);
20073 +
20074 + if (!vaddr) {
20075 + dev_err(fbdev->dev, "failed to ioremap framebuffer\n");
20076 + omap_vram_free(paddr, size);
20077 + return -ENOMEM;
20078 + }
20079 +
20080 + DBG("allocated VRAM paddr %lx, vaddr %p\n", paddr, vaddr);
20081 + } else {
20082 + void __iomem *va;
20083 +
20084 + r = omap_vrfb_request_ctx(&rg->vrfb);
20085 + if (r) {
20086 + dev_err(fbdev->dev, "vrfb create ctx failed\n");
20087 + return r;
20088 + }
20089 +
20090 + /* only ioremap the 0 angle view */
20091 + va = ioremap_wc(rg->vrfb.paddr[0], size);
20092 +
20093 + if (!va) {
20094 + printk(KERN_ERR "vrfb: ioremap failed\n");
20095 + omap_vrfb_release_ctx(&rg->vrfb);
20096 + return -ENOMEM;
20097 + }
20098 +
20099 + DBG("ioremapped vrfb area 0 to %p\n", va);
20100 +
20101 + rg->vrfb.vaddr[0] = va;
20102 +
20103 + vaddr = NULL;
20104 + }
20105 +
20106 + rg->paddr = paddr;
20107 + rg->vaddr = vaddr;
20108 + rg->size = size;
20109 + rg->alloc = 1;
20110 +
20111 + return 0;
20112 +}
20113 +
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)
20117 +{
20118 + struct omapfb_info *ofbi = FB2OFB(fbi);
20119 + struct omap_dss_device *display;
20120 + int bytespp;
20121 +
20122 + display = fb2display(fbi);
20123 +
20124 + if (!display)
20125 + return 0;
20126 +
20127 + switch (display->get_recommended_bpp(display)) {
20128 + case 16:
20129 + bytespp = 2;
20130 + break;
20131 + case 24:
20132 + bytespp = 4;
20133 + break;
20134 + default:
20135 + bytespp = 4;
20136 + break;
20137 + }
20138 +
20139 + if (!size) {
20140 + u16 w, h;
20141 +
20142 + display->get_resolution(display, &w, &h);
20143 +
20144 + if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
20145 +#ifdef DEBUG
20146 + int oldw = w, oldh = h;
20147 +#endif
20148 +
20149 + omap_vrfb_adjust_size(&w, &h, bytespp);
20150 +
20151 + /* Because we change the resolution of the 0 degree
20152 + * view, we need to alloc max(w, h) for height */
20153 + h = max(w, h);
20154 + w = OMAP_VRFB_LINE_LEN;
20155 +
20156 + DBG("adjusting fb mem size for VRFB, %dx%d -> %dx%d\n",
20157 + oldw, oldh, w, h);
20158 + }
20159 +
20160 + size = w * h * bytespp;
20161 + }
20162 +
20163 + if (!size)
20164 + return 0;
20165 +
20166 + return omapfb_alloc_fbmem(fbi, size, paddr);
20167 +}
20168 +
20169 +static enum omap_color_mode fb_format_to_dss_mode(enum omapfb_color_format fmt)
20170 +{
20171 + enum omap_color_mode mode;
20172 +
20173 + switch (fmt) {
20174 + case OMAPFB_COLOR_RGB565:
20175 + mode = OMAP_DSS_COLOR_RGB16;
20176 + break;
20177 + case OMAPFB_COLOR_YUV422:
20178 + mode = OMAP_DSS_COLOR_YUV2;
20179 + break;
20180 + case OMAPFB_COLOR_CLUT_8BPP:
20181 + mode = OMAP_DSS_COLOR_CLUT8;
20182 + break;
20183 + case OMAPFB_COLOR_CLUT_4BPP:
20184 + mode = OMAP_DSS_COLOR_CLUT4;
20185 + break;
20186 + case OMAPFB_COLOR_CLUT_2BPP:
20187 + mode = OMAP_DSS_COLOR_CLUT2;
20188 + break;
20189 + case OMAPFB_COLOR_CLUT_1BPP:
20190 + mode = OMAP_DSS_COLOR_CLUT1;
20191 + break;
20192 + case OMAPFB_COLOR_RGB444:
20193 + mode = OMAP_DSS_COLOR_RGB12U;
20194 + break;
20195 + case OMAPFB_COLOR_YUY422:
20196 + mode = OMAP_DSS_COLOR_UYVY;
20197 + break;
20198 + case OMAPFB_COLOR_ARGB16:
20199 + mode = OMAP_DSS_COLOR_ARGB16;
20200 + break;
20201 + case OMAPFB_COLOR_RGB24U:
20202 + mode = OMAP_DSS_COLOR_RGB24U;
20203 + break;
20204 + case OMAPFB_COLOR_RGB24P:
20205 + mode = OMAP_DSS_COLOR_RGB24P;
20206 + break;
20207 + case OMAPFB_COLOR_ARGB32:
20208 + mode = OMAP_DSS_COLOR_ARGB32;
20209 + break;
20210 + case OMAPFB_COLOR_RGBA32:
20211 + mode = OMAP_DSS_COLOR_RGBA32;
20212 + break;
20213 + case OMAPFB_COLOR_RGBX32:
20214 + mode = OMAP_DSS_COLOR_RGBX32;
20215 + break;
20216 + default:
20217 + mode = -EINVAL;
20218 + }
20219 +
20220 + return mode;
20221 +}
20222 +
20223 +static int omapfb_parse_vram_param(const char *param, int max_entries,
20224 + unsigned long *sizes, unsigned long *paddrs)
20225 +{
20226 + int fbnum;
20227 + unsigned long size;
20228 + unsigned long paddr = 0;
20229 + char *p, *start;
20230 +
20231 + start = (char *)param;
20232 +
20233 + while (1) {
20234 + p = start;
20235 +
20236 + fbnum = simple_strtoul(p, &p, 10);
20237 +
20238 + if (p == param)
20239 + return -EINVAL;
20240 +
20241 + if (*p != ':')
20242 + return -EINVAL;
20243 +
20244 + if (fbnum >= max_entries)
20245 + return -EINVAL;
20246 +
20247 + size = memparse(p + 1, &p);
20248 +
20249 + if (!size)
20250 + return -EINVAL;
20251 +
20252 + paddr = 0;
20253 +
20254 + if (*p == '@') {
20255 + paddr = simple_strtoul(p + 1, &p, 16);
20256 +
20257 + if (!paddr)
20258 + return -EINVAL;
20259 +
20260 + }
20261 +
20262 + paddrs[fbnum] = paddr;
20263 + sizes[fbnum] = size;
20264 +
20265 + if (*p == 0)
20266 + break;
20267 +
20268 + if (*p != ',')
20269 + return -EINVAL;
20270 +
20271 + ++p;
20272 +
20273 + start = p;
20274 + }
20275 +
20276 + return 0;
20277 +}
20278 +
20279 +static int omapfb_allocate_all_fbs(struct omapfb2_device *fbdev)
20280 +{
20281 + int i, r;
20282 + unsigned long vram_sizes[10];
20283 + unsigned long vram_paddrs[10];
20284 +
20285 + memset(&vram_sizes, 0, sizeof(vram_sizes));
20286 + memset(&vram_paddrs, 0, sizeof(vram_paddrs));
20287 +
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");
20291 +
20292 + memset(&vram_sizes, 0, sizeof(vram_sizes));
20293 + memset(&vram_paddrs, 0, sizeof(vram_paddrs));
20294 + }
20295 +
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;
20303 +
20304 + size = opd->mem_desc.region[i].size;
20305 + paddr = opd->mem_desc.region[i].paddr;
20306 +
20307 + vram_sizes[i] = size;
20308 + vram_paddrs[i] = paddr;
20309 + }
20310 + }
20311 + }
20312 +
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]);
20319 +
20320 + if (r)
20321 + return r;
20322 + }
20323 + }
20324 +
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;
20329 +
20330 + DBG("region%d phys %08x virt %p size=%lu\n",
20331 + i,
20332 + rg->paddr,
20333 + rg->vaddr,
20334 + rg->size);
20335 + }
20336 +
20337 + return 0;
20338 +}
20339 +
20340 +int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type)
20341 +{
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;
20349 + int r;
20350 +
20351 + if (type > OMAPFB_MEMTYPE_MAX)
20352 + return -EINVAL;
20353 +
20354 + size = PAGE_ALIGN(size);
20355 +
20356 + if (old_size == size && old_type == type)
20357 + return 0;
20358 +
20359 + if (display && display->sync)
20360 + display->sync(display);
20361 +
20362 + omapfb_free_fbmem(fbi);
20363 +
20364 + if (size == 0) {
20365 + clear_fb_info(fbi);
20366 + return 0;
20367 + }
20368 +
20369 + r = omapfb_alloc_fbmem(fbi, size, 0);
20370 +
20371 + if (r) {
20372 + if (old_size)
20373 + omapfb_alloc_fbmem(fbi, old_size, old_paddr);
20374 +
20375 + if (rg->size == 0)
20376 + clear_fb_info(fbi);
20377 +
20378 + return r;
20379 + }
20380 +
20381 + if (old_size == size)
20382 + return 0;
20383 +
20384 + if (old_size == 0) {
20385 + DBG("initializing fb %d\n", ofbi->id);
20386 + r = omapfb_fb_init(fbdev, fbi);
20387 + if (r) {
20388 + DBG("omapfb_fb_init failed\n");
20389 + goto err;
20390 + }
20391 + r = omapfb_apply_changes(fbi, 1);
20392 + if (r) {
20393 + DBG("omapfb_apply_changes failed\n");
20394 + goto err;
20395 + }
20396 + } else {
20397 + struct fb_var_screeninfo new_var;
20398 + memcpy(&new_var, &fbi->var, sizeof(new_var));
20399 + r = check_fb_var(fbi, &new_var);
20400 + if (r)
20401 + goto err;
20402 + memcpy(&fbi->var, &new_var, sizeof(fbi->var));
20403 + set_fb_fix(fbi);
20404 + }
20405 +
20406 + return 0;
20407 +err:
20408 + omapfb_free_fbmem(fbi);
20409 + clear_fb_info(fbi);
20410 + return r;
20411 +}
20412 +
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)
20415 +{
20416 + struct fb_var_screeninfo *var = &fbi->var;
20417 + struct omap_dss_device *display = fb2display(fbi);
20418 + struct omapfb_info *ofbi = FB2OFB(fbi);
20419 + int r = 0;
20420 +
20421 + fbi->fbops = &omapfb_ops;
20422 + fbi->flags = FBINFO_FLAG_DEFAULT;
20423 + fbi->pseudo_palette = fbdev->pseudo_palette;
20424 +
20425 + if (ofbi->region.size == 0) {
20426 + clear_fb_info(fbi);
20427 + return 0;
20428 + }
20429 +
20430 + var->nonstd = 0;
20431 + var->bits_per_pixel = 0;
20432 +
20433 + var->rotate = def_rotate;
20434 +
20435 + /*
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
20438 + * display bpp.
20439 + */
20440 + if (fbdev->dev->platform_data) {
20441 + struct omapfb_platform_data *opd;
20442 + int id = ofbi->id;
20443 +
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;
20448 +
20449 + format = opd->mem_desc.region[id].format;
20450 + mode = fb_format_to_dss_mode(format);
20451 + if (mode < 0) {
20452 + r = mode;
20453 + goto err;
20454 + }
20455 + r = dss_mode_to_fb_mode(mode, var);
20456 + if (r < 0)
20457 + goto err;
20458 + }
20459 + }
20460 +
20461 + if (display) {
20462 + u16 w, h;
20463 + int rotation = (var->rotate + ofbi->rotation[0]) % 4;
20464 +
20465 + display->get_resolution(display, &w, &h);
20466 +
20467 + if (rotation == FB_ROTATE_CW ||
20468 + rotation == FB_ROTATE_CCW) {
20469 + var->xres = h;
20470 + var->yres = w;
20471 + } else {
20472 + var->xres = w;
20473 + var->yres = h;
20474 + }
20475 +
20476 + var->xres_virtual = var->xres;
20477 + var->yres_virtual = var->yres;
20478 +
20479 + if (!var->bits_per_pixel) {
20480 + switch (display->get_recommended_bpp(display)) {
20481 + case 16:
20482 + var->bits_per_pixel = 16;
20483 + break;
20484 + case 24:
20485 + var->bits_per_pixel = 32;
20486 + break;
20487 + default:
20488 + dev_err(fbdev->dev, "illegal display "
20489 + "bpp\n");
20490 + return -EINVAL;
20491 + }
20492 + }
20493 + } else {
20494 + /* if there's no display, let's just guess some basic values */
20495 + var->xres = 320;
20496 + var->yres = 240;
20497 + var->xres_virtual = var->xres;
20498 + var->yres_virtual = var->yres;
20499 + if (!var->bits_per_pixel)
20500 + var->bits_per_pixel = 16;
20501 + }
20502 +
20503 + r = check_fb_var(fbi, var);
20504 + if (r)
20505 + goto err;
20506 +
20507 + set_fb_fix(fbi);
20508 +
20509 + r = fb_alloc_cmap(&fbi->cmap, 256, 0);
20510 + if (r)
20511 + dev_err(fbdev->dev, "unable to allocate color map memory\n");
20512 +
20513 +err:
20514 + return r;
20515 +}
20516 +
20517 +static void fbinfo_cleanup(struct omapfb2_device *fbdev, struct fb_info *fbi)
20518 +{
20519 + fb_dealloc_cmap(&fbi->cmap);
20520 +}
20521 +
20522 +
20523 +static void omapfb_free_resources(struct omapfb2_device *fbdev)
20524 +{
20525 + int i;
20526 +
20527 + DBG("free_resources\n");
20528 +
20529 + if (fbdev == NULL)
20530 + return;
20531 +
20532 + for (i = 0; i < fbdev->num_fbs; i++)
20533 + unregister_framebuffer(fbdev->fbs[i]);
20534 +
20535 + /* free the reserved fbmem */
20536 + omapfb_free_all_fbmem(fbdev);
20537 +
20538 + for (i = 0; i < fbdev->num_fbs; i++) {
20539 + fbinfo_cleanup(fbdev, fbdev->fbs[i]);
20540 + framebuffer_release(fbdev->fbs[i]);
20541 + }
20542 +
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]);
20546 +
20547 + omap_dss_put_device(fbdev->displays[i]);
20548 + }
20549 +
20550 + dev_set_drvdata(fbdev->dev, NULL);
20551 + kfree(fbdev);
20552 +}
20553 +
20554 +static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
20555 +{
20556 + int r, i;
20557 +
20558 + fbdev->num_fbs = 0;
20559 +
20560 + DBG("create %d framebuffers\n", CONFIG_FB_OMAP2_NUM_FBS);
20561 +
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;
20566 +
20567 + fbi = framebuffer_alloc(sizeof(struct omapfb_info),
20568 + fbdev->dev);
20569 +
20570 + if (fbi == NULL) {
20571 + dev_err(fbdev->dev,
20572 + "unable to allocate memory for plane info\n");
20573 + return -ENOMEM;
20574 + }
20575 +
20576 + clear_fb_info(fbi);
20577 +
20578 + fbdev->fbs[i] = fbi;
20579 +
20580 + ofbi = FB2OFB(fbi);
20581 + ofbi->fbdev = fbdev;
20582 + ofbi->id = i;
20583 +
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;
20588 +
20589 + fbdev->num_fbs++;
20590 + }
20591 +
20592 + DBG("fb_infos allocated\n");
20593 +
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]);
20597 +
20598 + ofbi->overlays[0] = fbdev->overlays[i];
20599 + ofbi->num_overlays = 1;
20600 + }
20601 +
20602 + /* allocate fb memories */
20603 + r = omapfb_allocate_all_fbs(fbdev);
20604 + if (r) {
20605 + dev_err(fbdev->dev, "failed to allocate fbmem\n");
20606 + return r;
20607 + }
20608 +
20609 + DBG("fbmems allocated\n");
20610 +
20611 + /* setup fb_infos */
20612 + for (i = 0; i < fbdev->num_fbs; i++) {
20613 + r = omapfb_fb_init(fbdev, fbdev->fbs[i]);
20614 + if (r) {
20615 + dev_err(fbdev->dev, "failed to setup fb_info\n");
20616 + return r;
20617 + }
20618 + }
20619 +
20620 + DBG("fb_infos initialized\n");
20621 +
20622 + for (i = 0; i < fbdev->num_fbs; i++) {
20623 + r = register_framebuffer(fbdev->fbs[i]);
20624 + if (r != 0) {
20625 + dev_err(fbdev->dev,
20626 + "registering framebuffer %d failed\n", i);
20627 + return r;
20628 + }
20629 + }
20630 +
20631 + DBG("framebuffers registered\n");
20632 +
20633 + for (i = 0; i < fbdev->num_fbs; i++) {
20634 + r = omapfb_apply_changes(fbdev->fbs[i], 1);
20635 + if (r) {
20636 + dev_err(fbdev->dev, "failed to change mode\n");
20637 + return r;
20638 + }
20639 + }
20640 +
20641 + DBG("create sysfs for fbs\n");
20642 + r = omapfb_create_sysfs(fbdev);
20643 + if (r) {
20644 + dev_err(fbdev->dev, "failed to create sysfs entries\n");
20645 + return r;
20646 + }
20647 +
20648 + /* Enable fb0 */
20649 + if (fbdev->num_fbs > 0) {
20650 + struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[0]);
20651 +
20652 + if (ofbi->num_overlays > 0) {
20653 + struct omap_overlay *ovl = ofbi->overlays[0];
20654 +
20655 + r = omapfb_overlay_enable(ovl, 1);
20656 +
20657 + if (r) {
20658 + dev_err(fbdev->dev,
20659 + "failed to enable overlay\n");
20660 + return r;
20661 + }
20662 + }
20663 + }
20664 +
20665 + DBG("create_framebuffers done\n");
20666 +
20667 + return 0;
20668 +}
20669 +
20670 +static int omapfb_mode_to_timings(const char *mode_str,
20671 + struct omap_video_timings *timings, u8 *bpp)
20672 +{
20673 + struct fb_info fbi;
20674 + struct fb_var_screeninfo var;
20675 + struct fb_ops fbops;
20676 + int r;
20677 +
20678 +#ifdef CONFIG_OMAP2_DSS_VENC
20679 + if (strcmp(mode_str, "pal") == 0) {
20680 + *timings = omap_dss_pal_timings;
20681 + *bpp = 0;
20682 + return 0;
20683 + } else if (strcmp(mode_str, "ntsc") == 0) {
20684 + *timings = omap_dss_ntsc_timings;
20685 + *bpp = 0;
20686 + return 0;
20687 + }
20688 +#endif
20689 +
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 */
20692 +
20693 + memset(&fbi, 0, sizeof(fbi));
20694 + memset(&var, 0, sizeof(var));
20695 + memset(&fbops, 0, sizeof(fbops));
20696 + fbi.fbops = &fbops;
20697 +
20698 + r = fb_find_mode(&var, &fbi, mode_str, NULL, 0, NULL, 24);
20699 +
20700 + if (r != 0) {
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;
20710 +
20711 + switch (var.bits_per_pixel) {
20712 + case 16:
20713 + *bpp = 16;
20714 + break;
20715 + case 24:
20716 + case 32:
20717 + default:
20718 + *bpp = 24;
20719 + break;
20720 + }
20721 +
20722 + return 0;
20723 + } else {
20724 + return -EINVAL;
20725 + }
20726 +}
20727 +
20728 +static int omapfb_set_def_mode(struct omap_dss_device *display, char *mode_str)
20729 +{
20730 + int r;
20731 + u8 bpp;
20732 + struct omap_video_timings timings;
20733 +
20734 + r = omapfb_mode_to_timings(mode_str, &timings, &bpp);
20735 + if (r)
20736 + return r;
20737 +
20738 + display->panel.recommended_bpp = bpp;
20739 +
20740 + if (!display->check_timings || !display->set_timings)
20741 + return -EINVAL;
20742 +
20743 + r = display->check_timings(display, &timings);
20744 + if (r)
20745 + return r;
20746 +
20747 + display->set_timings(display, &timings);
20748 +
20749 + return 0;
20750 +}
20751 +
20752 +static int omapfb_parse_def_modes(struct omapfb2_device *fbdev)
20753 +{
20754 + char *str, *options, *this_opt;
20755 + int r = 0;
20756 +
20757 + str = kmalloc(strlen(def_mode) + 1, GFP_KERNEL);
20758 + strcpy(str, def_mode);
20759 + options = str;
20760 +
20761 + while (!r && (this_opt = strsep(&options, ",")) != NULL) {
20762 + char *p, *display_str, *mode_str;
20763 + struct omap_dss_device *display;
20764 + int i;
20765 +
20766 + p = strchr(this_opt, ':');
20767 + if (!p) {
20768 + r = -EINVAL;
20769 + break;
20770 + }
20771 +
20772 + *p = 0;
20773 + display_str = this_opt;
20774 + mode_str = p + 1;
20775 +
20776 + display = NULL;
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];
20781 + break;
20782 + }
20783 + }
20784 +
20785 + if (!display) {
20786 + r = -EINVAL;
20787 + break;
20788 + }
20789 +
20790 + r = omapfb_set_def_mode(display, mode_str);
20791 + if (r)
20792 + break;
20793 + }
20794 +
20795 + kfree(str);
20796 +
20797 + return r;
20798 +}
20799 +
20800 +static int omapfb_probe(struct platform_device *pdev)
20801 +{
20802 + struct omapfb2_device *fbdev = NULL;
20803 + int r = 0;
20804 + int i;
20805 + struct omap_overlay *ovl;
20806 + struct omap_dss_device *def_display;
20807 + struct omap_dss_device *dssdev;
20808 +
20809 + DBG("omapfb_probe\n");
20810 +
20811 + if (pdev->num_resources != 0) {
20812 + dev_err(&pdev->dev, "probed for an unknown device\n");
20813 + r = -ENODEV;
20814 + goto err0;
20815 + }
20816 +
20817 + fbdev = kzalloc(sizeof(struct omapfb2_device), GFP_KERNEL);
20818 + if (fbdev == NULL) {
20819 + r = -ENOMEM;
20820 + goto err0;
20821 + }
20822 +
20823 + mutex_init(&fbdev->mtx);
20824 +
20825 + fbdev->dev = &pdev->dev;
20826 + platform_set_drvdata(pdev, fbdev);
20827 +
20828 + fbdev->num_displays = 0;
20829 + dssdev = NULL;
20830 + for_each_dss_dev(dssdev) {
20831 + omap_dss_get_device(dssdev);
20832 + fbdev->displays[fbdev->num_displays++] = dssdev;
20833 + }
20834 +
20835 + if (fbdev->num_displays == 0) {
20836 + dev_err(&pdev->dev, "no displays\n");
20837 + r = -EINVAL;
20838 + goto cleanup;
20839 + }
20840 +
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);
20844 +
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);
20848 +
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");
20852 + }
20853 +
20854 + r = omapfb_create_framebuffers(fbdev);
20855 + if (r)
20856 + goto cleanup;
20857 +
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);
20862 + if (r)
20863 + dev_warn(fbdev->dev, "failed to apply dispc config\n");
20864 + }
20865 +
20866 + DBG("mgr->apply'ed\n");
20867 +
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;
20873 + } else {
20874 + dev_warn(&pdev->dev, "cannot find default display\n");
20875 + def_display = NULL;
20876 + }
20877 +
20878 + if (def_display) {
20879 + u16 w, h;
20880 + r = def_display->enable(def_display);
20881 + if (r)
20882 + dev_warn(fbdev->dev, "Failed to enable display '%s'\n",
20883 + def_display->name);
20884 +
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);
20899 +
20900 + def_display->get_resolution(def_display, &w, &h);
20901 + def_display->update(def_display, 0, 0, w, h);
20902 +#endif
20903 + } else {
20904 + if (def_display->set_update_mode)
20905 + def_display->set_update_mode(def_display,
20906 + OMAP_DSS_UPDATE_AUTO);
20907 + }
20908 + }
20909 +
20910 + return 0;
20911 +
20912 +cleanup:
20913 + omapfb_free_resources(fbdev);
20914 +err0:
20915 + dev_err(&pdev->dev, "failed to setup omapfb\n");
20916 + return r;
20917 +}
20918 +
20919 +static int omapfb_remove(struct platform_device *pdev)
20920 +{
20921 + struct omapfb2_device *fbdev = platform_get_drvdata(pdev);
20922 +
20923 + /* FIXME: wait till completion of pending events */
20924 +
20925 + omapfb_remove_sysfs(fbdev);
20926 +
20927 + omapfb_free_resources(fbdev);
20928 +
20929 + return 0;
20930 +}
20931 +
20932 +static struct platform_driver omapfb_driver = {
20933 + .probe = omapfb_probe,
20934 + .remove = omapfb_remove,
20935 + .driver = {
20936 + .name = "omapfb",
20937 + .owner = THIS_MODULE,
20938 + },
20939 +};
20940 +
20941 +static int __init omapfb_init(void)
20942 +{
20943 + DBG("omapfb_init\n");
20944 +
20945 + if (platform_driver_register(&omapfb_driver)) {
20946 + printk(KERN_ERR "failed to register omapfb driver\n");
20947 + return -ENODEV;
20948 + }
20949 +
20950 + return 0;
20951 +}
20952 +
20953 +static void __exit omapfb_exit(void)
20954 +{
20955 + DBG("omapfb_exit\n");
20956 + platform_driver_unregister(&omapfb_driver);
20957 +}
20958 +
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);
20964 +
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);
20971 +
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
20978 --- /dev/null
20979 +++ b/drivers/video/omap2/omapfb/omapfb-sysfs.c
20980 @@ -0,0 +1,507 @@
20981 +/*
20982 + * linux/drivers/video/omap2/omapfb-sysfs.c
20983 + *
20984 + * Copyright (C) 2008 Nokia Corporation
20985 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
20986 + *
20987 + * Some code and ideas taken from drivers/video/omap/ driver
20988 + * by Imre Deak.
20989 + *
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.
20993 + *
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
20997 + * more details.
20998 + *
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/>.
21001 + */
21002 +
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>
21011 +
21012 +#include <mach/display.h>
21013 +#include <mach/vrfb.h>
21014 +
21015 +#include "omapfb.h"
21016 +
21017 +static ssize_t show_rotate_type(struct device *dev,
21018 + struct device_attribute *attr, char *buf)
21019 +{
21020 + struct fb_info *fbi = dev_get_drvdata(dev);
21021 + struct omapfb_info *ofbi = FB2OFB(fbi);
21022 +
21023 + return snprintf(buf, PAGE_SIZE, "%d\n", ofbi->rotation_type);
21024 +}
21025 +
21026 +static ssize_t store_rotate_type(struct device *dev,
21027 + struct device_attribute *attr,
21028 + const char *buf, size_t count)
21029 +{
21030 + struct fb_info *fbi = dev_get_drvdata(dev);
21031 + struct omapfb_info *ofbi = FB2OFB(fbi);
21032 + enum omap_dss_rotation_type rot_type;
21033 + int r;
21034 +
21035 + rot_type = simple_strtoul(buf, NULL, 0);
21036 +
21037 + if (rot_type != OMAP_DSS_ROT_DMA && rot_type != OMAP_DSS_ROT_VRFB)
21038 + return -EINVAL;
21039 +
21040 + lock_fb_info(fbi);
21041 +
21042 + r = 0;
21043 + if (rot_type == ofbi->rotation_type)
21044 + goto out;
21045 +
21046 + if (ofbi->region.size) {
21047 + r = -EBUSY;
21048 + goto out;
21049 + }
21050 +
21051 + ofbi->rotation_type = rot_type;
21052 +
21053 + /*
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.
21056 + */
21057 +out:
21058 + unlock_fb_info(fbi);
21059 +
21060 + return r ? r : count;
21061 +}
21062 +
21063 +
21064 +static ssize_t show_mirror(struct device *dev,
21065 + struct device_attribute *attr, char *buf)
21066 +{
21067 + struct fb_info *fbi = dev_get_drvdata(dev);
21068 + struct omapfb_info *ofbi = FB2OFB(fbi);
21069 +
21070 + return snprintf(buf, PAGE_SIZE, "%d\n", ofbi->mirror);
21071 +}
21072 +
21073 +static ssize_t store_mirror(struct device *dev,
21074 + struct device_attribute *attr,
21075 + const char *buf, size_t count)
21076 +{
21077 + struct fb_info *fbi = dev_get_drvdata(dev);
21078 + struct omapfb_info *ofbi = FB2OFB(fbi);
21079 + bool mirror;
21080 + int r;
21081 + struct fb_var_screeninfo new_var;
21082 +
21083 + mirror = simple_strtoul(buf, NULL, 0);
21084 +
21085 + if (mirror != 0 && mirror != 1)
21086 + return -EINVAL;
21087 +
21088 + lock_fb_info(fbi);
21089 +
21090 + ofbi->mirror = mirror;
21091 +
21092 + memcpy(&new_var, &fbi->var, sizeof(new_var));
21093 + r = check_fb_var(fbi, &new_var);
21094 + if (r)
21095 + goto out;
21096 + memcpy(&fbi->var, &new_var, sizeof(fbi->var));
21097 +
21098 + set_fb_fix(fbi);
21099 +
21100 + r = omapfb_apply_changes(fbi, 0);
21101 + if (r)
21102 + goto out;
21103 +
21104 + r = count;
21105 +out:
21106 + unlock_fb_info(fbi);
21107 +
21108 + return r;
21109 +}
21110 +
21111 +static ssize_t show_overlays(struct device *dev,
21112 + struct device_attribute *attr, char *buf)
21113 +{
21114 + struct fb_info *fbi = dev_get_drvdata(dev);
21115 + struct omapfb_info *ofbi = FB2OFB(fbi);
21116 + struct omapfb2_device *fbdev = ofbi->fbdev;
21117 + ssize_t l = 0;
21118 + int t;
21119 +
21120 + omapfb_lock(fbdev);
21121 + lock_fb_info(fbi);
21122 +
21123 + for (t = 0; t < ofbi->num_overlays; t++) {
21124 + struct omap_overlay *ovl = ofbi->overlays[t];
21125 + int ovlnum;
21126 +
21127 + for (ovlnum = 0; ovlnum < fbdev->num_overlays; ++ovlnum)
21128 + if (ovl == fbdev->overlays[ovlnum])
21129 + break;
21130 +
21131 + l += snprintf(buf + l, PAGE_SIZE - l, "%s%d",
21132 + t == 0 ? "" : ",", ovlnum);
21133 + }
21134 +
21135 + l += snprintf(buf + l, PAGE_SIZE - l, "\n");
21136 +
21137 + unlock_fb_info(fbi);
21138 + omapfb_unlock(fbdev);
21139 +
21140 + return l;
21141 +}
21142 +
21143 +static struct omapfb_info *get_overlay_fb(struct omapfb2_device *fbdev,
21144 + struct omap_overlay *ovl)
21145 +{
21146 + int i, t;
21147 +
21148 + for (i = 0; i < fbdev->num_fbs; i++) {
21149 + struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
21150 +
21151 + for (t = 0; t < ofbi->num_overlays; t++) {
21152 + if (ofbi->overlays[t] == ovl)
21153 + return ofbi;
21154 + }
21155 + }
21156 +
21157 + return NULL;
21158 +}
21159 +
21160 +static ssize_t store_overlays(struct device *dev, struct device_attribute *attr,
21161 + const char *buf, size_t count)
21162 +{
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;
21169 + int len;
21170 + bool added = false;
21171 +
21172 + num_ovls = 0;
21173 +
21174 + len = strlen(buf);
21175 + if (buf[len - 1] == '\n')
21176 + len = len - 1;
21177 +
21178 + omapfb_lock(fbdev);
21179 + lock_fb_info(fbi);
21180 +
21181 + if (len > 0) {
21182 + char *p = (char *)buf;
21183 + int ovlnum;
21184 +
21185 + while (p < buf + len) {
21186 + int found;
21187 + if (num_ovls == OMAPFB_MAX_OVL_PER_FB) {
21188 + r = -EINVAL;
21189 + goto out;
21190 + }
21191 +
21192 + ovlnum = simple_strtoul(p, &p, 0);
21193 + if (ovlnum > fbdev->num_overlays) {
21194 + r = -EINVAL;
21195 + goto out;
21196 + }
21197 +
21198 + found = 0;
21199 + for (i = 0; i < num_ovls; ++i) {
21200 + if (ovls[i] == fbdev->overlays[ovlnum]) {
21201 + found = 1;
21202 + break;
21203 + }
21204 + }
21205 +
21206 + if (!found)
21207 + ovls[num_ovls++] = fbdev->overlays[ovlnum];
21208 +
21209 + p++;
21210 + }
21211 + }
21212 +
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");
21217 + r = -EINVAL;
21218 + goto out;
21219 + }
21220 + }
21221 +
21222 + /* detach unused overlays */
21223 + for (i = 0; i < ofbi->num_overlays; ++i) {
21224 + int t, found;
21225 +
21226 + ovl = ofbi->overlays[i];
21227 +
21228 + found = 0;
21229 +
21230 + for (t = 0; t < num_ovls; ++t) {
21231 + if (ovl == ovls[t]) {
21232 + found = 1;
21233 + break;
21234 + }
21235 + }
21236 +
21237 + if (found)
21238 + continue;
21239 +
21240 + DBG("detaching %d\n", ofbi->overlays[i]->id);
21241 +
21242 + omapfb_overlay_enable(ovl, 0);
21243 +
21244 + if (ovl->manager)
21245 + ovl->manager->apply(ovl->manager);
21246 +
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];
21250 + }
21251 +
21252 + ofbi->num_overlays--;
21253 + i--;
21254 + }
21255 +
21256 + for (i = 0; i < num_ovls; ++i) {
21257 + int t, found;
21258 +
21259 + ovl = ovls[i];
21260 +
21261 + found = 0;
21262 +
21263 + for (t = 0; t < ofbi->num_overlays; ++t) {
21264 + if (ovl == ofbi->overlays[t]) {
21265 + found = 1;
21266 + break;
21267 + }
21268 + }
21269 +
21270 + if (found)
21271 + continue;
21272 + ofbi->rotation[ofbi->num_overlays] = 0;
21273 + ofbi->overlays[ofbi->num_overlays++] = ovl;
21274 +
21275 + added = true;
21276 + }
21277 +
21278 + if (added) {
21279 + r = omapfb_apply_changes(fbi, 0);
21280 + if (r)
21281 + goto out;
21282 + }
21283 +
21284 + r = count;
21285 +out:
21286 + unlock_fb_info(fbi);
21287 + omapfb_unlock(fbdev);
21288 +
21289 + return r;
21290 +}
21291 +
21292 +static ssize_t show_overlays_rotate(struct device *dev,
21293 + struct device_attribute *attr, char *buf)
21294 +{
21295 + struct fb_info *fbi = dev_get_drvdata(dev);
21296 + struct omapfb_info *ofbi = FB2OFB(fbi);
21297 + ssize_t l = 0;
21298 + int t;
21299 +
21300 + lock_fb_info(fbi);
21301 +
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]);
21305 + }
21306 +
21307 + l += snprintf(buf + l, PAGE_SIZE - l, "\n");
21308 +
21309 + unlock_fb_info(fbi);
21310 +
21311 + return l;
21312 +}
21313 +
21314 +static ssize_t store_overlays_rotate(struct device *dev,
21315 + struct device_attribute *attr, const char *buf, size_t count)
21316 +{
21317 + struct fb_info *fbi = dev_get_drvdata(dev);
21318 + struct omapfb_info *ofbi = FB2OFB(fbi);
21319 + int num_ovls = 0, r, i;
21320 + int len;
21321 + bool changed = false;
21322 + u8 rotation[OMAPFB_MAX_OVL_PER_FB];
21323 +
21324 + len = strlen(buf);
21325 + if (buf[len - 1] == '\n')
21326 + len = len - 1;
21327 +
21328 + lock_fb_info(fbi);
21329 +
21330 + if (len > 0) {
21331 + char *p = (char *)buf;
21332 +
21333 + while (p < buf + len) {
21334 + int rot;
21335 +
21336 + if (num_ovls == ofbi->num_overlays) {
21337 + r = -EINVAL;
21338 + goto out;
21339 + }
21340 +
21341 + rot = simple_strtoul(p, &p, 0);
21342 + if (rot < 0 || rot > 3) {
21343 + r = -EINVAL;
21344 + goto out;
21345 + }
21346 +
21347 + if (ofbi->rotation[num_ovls] != rot)
21348 + changed = true;
21349 +
21350 + rotation[num_ovls++] = rot;
21351 +
21352 + p++;
21353 + }
21354 + }
21355 +
21356 + if (num_ovls != ofbi->num_overlays) {
21357 + r = -EINVAL;
21358 + goto out;
21359 + }
21360 +
21361 + if (changed) {
21362 + for (i = 0; i < num_ovls; ++i)
21363 + ofbi->rotation[i] = rotation[i];
21364 +
21365 + r = omapfb_apply_changes(fbi, 0);
21366 + if (r)
21367 + goto out;
21368 +
21369 + /* FIXME error handling? */
21370 + }
21371 +
21372 + r = count;
21373 +out:
21374 + unlock_fb_info(fbi);
21375 +
21376 + return r;
21377 +}
21378 +
21379 +static ssize_t show_size(struct device *dev,
21380 + struct device_attribute *attr, char *buf)
21381 +{
21382 + struct fb_info *fbi = dev_get_drvdata(dev);
21383 + struct omapfb_info *ofbi = FB2OFB(fbi);
21384 +
21385 + return snprintf(buf, PAGE_SIZE, "%lu\n", ofbi->region.size);
21386 +}
21387 +
21388 +static ssize_t store_size(struct device *dev, struct device_attribute *attr,
21389 + const char *buf, size_t count)
21390 +{
21391 + struct fb_info *fbi = dev_get_drvdata(dev);
21392 + struct omapfb_info *ofbi = FB2OFB(fbi);
21393 + unsigned long size;
21394 + int r;
21395 + int i;
21396 +
21397 + size = PAGE_ALIGN(simple_strtoul(buf, NULL, 0));
21398 +
21399 + lock_fb_info(fbi);
21400 +
21401 + for (i = 0; i < ofbi->num_overlays; i++) {
21402 + if (ofbi->overlays[i]->info.enabled) {
21403 + r = -EBUSY;
21404 + goto out;
21405 + }
21406 + }
21407 +
21408 + if (size != ofbi->region.size) {
21409 + r = omapfb_realloc_fbmem(fbi, size, ofbi->region.type);
21410 + if (r) {
21411 + dev_err(dev, "realloc fbmem failed\n");
21412 + goto out;
21413 + }
21414 + }
21415 +
21416 + r = count;
21417 +out:
21418 + unlock_fb_info(fbi);
21419 +
21420 + return r;
21421 +}
21422 +
21423 +static ssize_t show_phys(struct device *dev,
21424 + struct device_attribute *attr, char *buf)
21425 +{
21426 + struct fb_info *fbi = dev_get_drvdata(dev);
21427 + struct omapfb_info *ofbi = FB2OFB(fbi);
21428 +
21429 + return snprintf(buf, PAGE_SIZE, "%0x\n", ofbi->region.paddr);
21430 +}
21431 +
21432 +static ssize_t show_virt(struct device *dev,
21433 + struct device_attribute *attr, char *buf)
21434 +{
21435 + struct fb_info *fbi = dev_get_drvdata(dev);
21436 + struct omapfb_info *ofbi = FB2OFB(fbi);
21437 +
21438 + return snprintf(buf, PAGE_SIZE, "%p\n", ofbi->region.vaddr);
21439 +}
21440 +
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),
21451 +};
21452 +
21453 +int omapfb_create_sysfs(struct omapfb2_device *fbdev)
21454 +{
21455 + int i;
21456 + int r;
21457 +
21458 + DBG("create sysfs for fbs\n");
21459 + for (i = 0; i < fbdev->num_fbs; i++) {
21460 + int t;
21461 + for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++) {
21462 + r = device_create_file(fbdev->fbs[i]->dev,
21463 + &omapfb_attrs[t]);
21464 +
21465 + if (r) {
21466 + dev_err(fbdev->dev, "failed to create sysfs "
21467 + "file\n");
21468 + return r;
21469 + }
21470 + }
21471 + }
21472 +
21473 + return 0;
21474 +}
21475 +
21476 +void omapfb_remove_sysfs(struct omapfb2_device *fbdev)
21477 +{
21478 + int i, t;
21479 +
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]);
21485 + }
21486 +}
21487 +
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
21491 --- /dev/null
21492 +++ b/drivers/video/omap2/omapfb/omapfb.h
21493 @@ -0,0 +1,146 @@
21494 +/*
21495 + * linux/drivers/video/omap2/omapfb.h
21496 + *
21497 + * Copyright (C) 2008 Nokia Corporation
21498 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
21499 + *
21500 + * Some code and ideas taken from drivers/video/omap/ driver
21501 + * by Imre Deak.
21502 + *
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.
21506 + *
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
21510 + * more details.
21511 + *
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/>.
21514 + */
21515 +
21516 +#ifndef __DRIVERS_VIDEO_OMAP2_OMAPFB_H__
21517 +#define __DRIVERS_VIDEO_OMAP2_OMAPFB_H__
21518 +
21519 +#ifdef CONFIG_FB_OMAP2_DEBUG_SUPPORT
21520 +#define DEBUG
21521 +#endif
21522 +
21523 +#include <mach/display.h>
21524 +
21525 +#ifdef DEBUG
21526 +extern unsigned int omapfb_debug;
21527 +#define DBG(format, ...) \
21528 + if (omapfb_debug) \
21529 + printk(KERN_DEBUG "OMAPFB: " format, ## __VA_ARGS__)
21530 +#else
21531 +#define DBG(format, ...)
21532 +#endif
21533 +
21534 +#define FB2OFB(fb_info) ((struct omapfb_info *)(fb_info->par))
21535 +
21536 +/* max number of overlays to which a framebuffer data can be direct */
21537 +#define OMAPFB_MAX_OVL_PER_FB 3
21538 +
21539 +struct omapfb2_mem_region {
21540 + u32 paddr;
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 */
21547 +};
21548 +
21549 +/* appended to fb_info */
21550 +struct omapfb_info {
21551 + int id;
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];
21559 + bool mirror;
21560 +};
21561 +
21562 +struct omapfb2_device {
21563 + struct device *dev;
21564 + struct mutex mtx;
21565 +
21566 + u32 pseudo_palette[17];
21567 +
21568 + int state;
21569 +
21570 + unsigned num_fbs;
21571 + struct fb_info *fbs[10];
21572 +
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];
21579 +};
21580 +
21581 +struct omapfb_colormode {
21582 + enum omap_color_mode dssmode;
21583 + u32 bits_per_pixel;
21584 + u32 nonstd;
21585 + struct fb_bitfield red;
21586 + struct fb_bitfield green;
21587 + struct fb_bitfield blue;
21588 + struct fb_bitfield transp;
21589 +};
21590 +
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);
21595 +
21596 +int omapfb_create_sysfs(struct omapfb2_device *fbdev);
21597 +void omapfb_remove_sysfs(struct omapfb2_device *fbdev);
21598 +
21599 +int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg);
21600 +
21601 +int dss_mode_to_fb_mode(enum omap_color_mode dssmode,
21602 + struct fb_var_screeninfo *var);
21603 +
21604 +/* find the display connected to this fb, if any */
21605 +static inline struct omap_dss_device *fb2display(struct fb_info *fbi)
21606 +{
21607 + struct omapfb_info *ofbi = FB2OFB(fbi);
21608 + int i;
21609 +
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;
21614 + }
21615 +
21616 + return NULL;
21617 +}
21618 +
21619 +static inline void omapfb_lock(struct omapfb2_device *fbdev)
21620 +{
21621 + mutex_lock(&fbdev->mtx);
21622 +}
21623 +
21624 +static inline void omapfb_unlock(struct omapfb2_device *fbdev)
21625 +{
21626 + mutex_unlock(&fbdev->mtx);
21627 +}
21628 +
21629 +static inline int omapfb_overlay_enable(struct omap_overlay *ovl,
21630 + int enable)
21631 +{
21632 + struct omap_overlay_info info;
21633 +
21634 + ovl->get_overlay_info(ovl, &info);
21635 + info.enabled = enable;
21636 + return ovl->set_overlay_info(ovl, &info);
21637 +}
21638 +
21639 +#endif
21640 diff --git a/drivers/video/omap2/vram.c b/drivers/video/omap2/vram.c
21641 new file mode 100644
21642 index 0000000..634ce23
21643 --- /dev/null
21644 +++ b/drivers/video/omap2/vram.c
21645 @@ -0,0 +1,655 @@
21646 +/*
21647 + * VRAM manager for OMAP
21648 + *
21649 + * Copyright (C) 2009 Nokia Corporation
21650 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
21651 + *
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.
21655 + *
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.
21660 + *
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.
21664 + */
21665 +
21666 +/*#define DEBUG*/
21667 +
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>
21677 +
21678 +#include <asm/setup.h>
21679 +
21680 +#include <mach/sram.h>
21681 +#include <mach/vram.h>
21682 +#include <mach/dma.h>
21683 +
21684 +#ifdef DEBUG
21685 +#define DBG(format, ...) pr_debug("VRAM: " format, ## __VA_ARGS__)
21686 +#else
21687 +#define DBG(format, ...)
21688 +#endif
21689 +
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 */
21693 +
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
21697 +
21698 +static bool vram_initialized;
21699 +static int postponed_cnt;
21700 +static struct {
21701 + unsigned long paddr;
21702 + size_t size;
21703 +} postponed_regions[MAX_POSTPONED_REGIONS];
21704 +
21705 +struct vram_alloc {
21706 + struct list_head list;
21707 + unsigned long paddr;
21708 + unsigned pages;
21709 +};
21710 +
21711 +struct vram_region {
21712 + struct list_head list;
21713 + struct list_head alloc_list;
21714 + unsigned long paddr;
21715 + unsigned pages;
21716 +};
21717 +
21718 +static DEFINE_MUTEX(region_mutex);
21719 +static LIST_HEAD(region_list);
21720 +
21721 +static inline int region_mem_type(unsigned long paddr)
21722 +{
21723 + if (paddr >= OMAP2_SRAM_START &&
21724 + paddr < OMAP2_SRAM_START + OMAP2_SRAM_SIZE)
21725 + return OMAP_VRAM_MEMTYPE_SRAM;
21726 + else
21727 + return OMAP_VRAM_MEMTYPE_SDRAM;
21728 +}
21729 +
21730 +static struct vram_region *omap_vram_create_region(unsigned long paddr,
21731 + unsigned pages)
21732 +{
21733 + struct vram_region *rm;
21734 +
21735 + rm = kzalloc(sizeof(*rm), GFP_KERNEL);
21736 +
21737 + if (rm) {
21738 + INIT_LIST_HEAD(&rm->alloc_list);
21739 + rm->paddr = paddr;
21740 + rm->pages = pages;
21741 + }
21742 +
21743 + return rm;
21744 +}
21745 +
21746 +#if 0
21747 +static void omap_vram_free_region(struct vram_region *vr)
21748 +{
21749 + list_del(&vr->list);
21750 + kfree(vr);
21751 +}
21752 +#endif
21753 +
21754 +static struct vram_alloc *omap_vram_create_allocation(struct vram_region *vr,
21755 + unsigned long paddr, unsigned pages)
21756 +{
21757 + struct vram_alloc *va;
21758 + struct vram_alloc *new;
21759 +
21760 + new = kzalloc(sizeof(*va), GFP_KERNEL);
21761 +
21762 + if (!new)
21763 + return NULL;
21764 +
21765 + new->paddr = paddr;
21766 + new->pages = pages;
21767 +
21768 + list_for_each_entry(va, &vr->alloc_list, list) {
21769 + if (va->paddr > new->paddr)
21770 + break;
21771 + }
21772 +
21773 + list_add_tail(&new->list, &va->list);
21774 +
21775 + return new;
21776 +}
21777 +
21778 +static void omap_vram_free_allocation(struct vram_alloc *va)
21779 +{
21780 + list_del(&va->list);
21781 + kfree(va);
21782 +}
21783 +
21784 +int omap_vram_add_region(unsigned long paddr, size_t size)
21785 +{
21786 + struct vram_region *rm;
21787 + unsigned pages;
21788 +
21789 + if (vram_initialized) {
21790 + DBG("adding region paddr %08lx size %d\n",
21791 + paddr, size);
21792 +
21793 + size &= PAGE_MASK;
21794 + pages = size >> PAGE_SHIFT;
21795 +
21796 + rm = omap_vram_create_region(paddr, pages);
21797 + if (rm == NULL)
21798 + return -ENOMEM;
21799 +
21800 + list_add(&rm->list, &region_list);
21801 + } else {
21802 + if (postponed_cnt == MAX_POSTPONED_REGIONS)
21803 + return -ENOMEM;
21804 +
21805 + postponed_regions[postponed_cnt].paddr = paddr;
21806 + postponed_regions[postponed_cnt].size = size;
21807 +
21808 + ++postponed_cnt;
21809 + }
21810 + return 0;
21811 +}
21812 +
21813 +int omap_vram_free(unsigned long paddr, size_t size)
21814 +{
21815 + struct vram_region *rm;
21816 + struct vram_alloc *alloc;
21817 + unsigned start, end;
21818 +
21819 + DBG("free mem paddr %08lx size %d\n", paddr, size);
21820 +
21821 + size = PAGE_ALIGN(size);
21822 +
21823 + mutex_lock(&region_mutex);
21824 +
21825 + list_for_each_entry(rm, &region_list, list) {
21826 + list_for_each_entry(alloc, &rm->alloc_list, list) {
21827 + start = alloc->paddr;
21828 + end = alloc->paddr + (alloc->pages >> PAGE_SHIFT);
21829 +
21830 + if (start >= paddr && end < paddr + size)
21831 + goto found;
21832 + }
21833 + }
21834 +
21835 + mutex_unlock(&region_mutex);
21836 + return -EINVAL;
21837 +
21838 +found:
21839 + omap_vram_free_allocation(alloc);
21840 +
21841 + mutex_unlock(&region_mutex);
21842 + return 0;
21843 +}
21844 +EXPORT_SYMBOL(omap_vram_free);
21845 +
21846 +static int _omap_vram_reserve(unsigned long paddr, unsigned pages)
21847 +{
21848 + struct vram_region *rm;
21849 + struct vram_alloc *alloc;
21850 + size_t size;
21851 +
21852 + size = pages << PAGE_SHIFT;
21853 +
21854 + list_for_each_entry(rm, &region_list, list) {
21855 + unsigned long start, end;
21856 +
21857 + DBG("checking region %lx %d\n", rm->paddr, rm->pages);
21858 +
21859 + if (region_mem_type(rm->paddr) != region_mem_type(paddr))
21860 + continue;
21861 +
21862 + start = rm->paddr;
21863 + end = start + (rm->pages << PAGE_SHIFT) - 1;
21864 + if (start > paddr || end < paddr + size - 1)
21865 + continue;
21866 +
21867 + DBG("block ok, checking allocs\n");
21868 +
21869 + list_for_each_entry(alloc, &rm->alloc_list, list) {
21870 + end = alloc->paddr - 1;
21871 +
21872 + if (start <= paddr && end >= paddr + size - 1)
21873 + goto found;
21874 +
21875 + start = alloc->paddr + (alloc->pages << PAGE_SHIFT);
21876 + }
21877 +
21878 + end = rm->paddr + (rm->pages << PAGE_SHIFT) - 1;
21879 +
21880 + if (!(start <= paddr && end >= paddr + size - 1))
21881 + continue;
21882 +found:
21883 + DBG("found area start %lx, end %lx\n", start, end);
21884 +
21885 + if (omap_vram_create_allocation(rm, paddr, pages) == NULL)
21886 + return -ENOMEM;
21887 +
21888 + return 0;
21889 + }
21890 +
21891 + return -ENOMEM;
21892 +}
21893 +
21894 +int omap_vram_reserve(unsigned long paddr, size_t size)
21895 +{
21896 + unsigned pages;
21897 + int r;
21898 +
21899 + DBG("reserve mem paddr %08lx size %d\n", paddr, size);
21900 +
21901 + size = PAGE_ALIGN(size);
21902 + pages = size >> PAGE_SHIFT;
21903 +
21904 + mutex_lock(&region_mutex);
21905 +
21906 + r = _omap_vram_reserve(paddr, pages);
21907 +
21908 + mutex_unlock(&region_mutex);
21909 +
21910 + return r;
21911 +}
21912 +EXPORT_SYMBOL(omap_vram_reserve);
21913 +
21914 +static void _omap_vram_dma_cb(int lch, u16 ch_status, void *data)
21915 +{
21916 + struct completion *compl = data;
21917 + complete(compl);
21918 +}
21919 +
21920 +static int _omap_vram_clear(u32 paddr, unsigned pages)
21921 +{
21922 + struct completion compl;
21923 + unsigned elem_count;
21924 + unsigned frame_count;
21925 + int r;
21926 + int lch;
21927 +
21928 + init_completion(&compl);
21929 +
21930 + r = omap_request_dma(OMAP_DMA_NO_DEVICE, "VRAM DMA",
21931 + _omap_vram_dma_cb,
21932 + &compl, &lch);
21933 + if (r) {
21934 + pr_err("VRAM: request_dma failed for memory clear\n");
21935 + return -EBUSY;
21936 + }
21937 +
21938 + elem_count = pages * PAGE_SIZE / 4;
21939 + frame_count = 1;
21940 +
21941 + omap_set_dma_transfer_params(lch, OMAP_DMA_DATA_TYPE_S32,
21942 + elem_count, frame_count,
21943 + OMAP_DMA_SYNC_ELEMENT,
21944 + 0, 0);
21945 +
21946 + omap_set_dma_dest_params(lch, 0, OMAP_DMA_AMODE_POST_INC,
21947 + paddr, 0, 0);
21948 +
21949 + omap_set_dma_color_mode(lch, OMAP_DMA_CONSTANT_FILL, 0x000000);
21950 +
21951 + omap_start_dma(lch);
21952 +
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");
21956 + r = -EIO;
21957 + goto err;
21958 + }
21959 +
21960 + r = 0;
21961 +err:
21962 + omap_free_dma(lch);
21963 +
21964 + return r;
21965 +}
21966 +
21967 +static int _omap_vram_alloc(int mtype, unsigned pages, unsigned long *paddr)
21968 +{
21969 + struct vram_region *rm;
21970 + struct vram_alloc *alloc;
21971 +
21972 + list_for_each_entry(rm, &region_list, list) {
21973 + unsigned long start, end;
21974 +
21975 + DBG("checking region %lx %d\n", rm->paddr, rm->pages);
21976 +
21977 + if (region_mem_type(rm->paddr) != mtype)
21978 + continue;
21979 +
21980 + start = rm->paddr;
21981 +
21982 + list_for_each_entry(alloc, &rm->alloc_list, list) {
21983 + end = alloc->paddr;
21984 +
21985 + if (end - start >= pages << PAGE_SHIFT)
21986 + goto found;
21987 +
21988 + start = alloc->paddr + (alloc->pages << PAGE_SHIFT);
21989 + }
21990 +
21991 + end = rm->paddr + (rm->pages << PAGE_SHIFT);
21992 +found:
21993 + if (end - start < pages << PAGE_SHIFT)
21994 + continue;
21995 +
21996 + DBG("found %lx, end %lx\n", start, end);
21997 +
21998 + alloc = omap_vram_create_allocation(rm, start, pages);
21999 + if (alloc == NULL)
22000 + return -ENOMEM;
22001 +
22002 + *paddr = start;
22003 +
22004 + _omap_vram_clear(start, pages);
22005 +
22006 + return 0;
22007 + }
22008 +
22009 + return -ENOMEM;
22010 +}
22011 +
22012 +int omap_vram_alloc(int mtype, size_t size, unsigned long *paddr)
22013 +{
22014 + unsigned pages;
22015 + int r;
22016 +
22017 + BUG_ON(mtype > OMAP_VRAM_MEMTYPE_MAX || !size);
22018 +
22019 + DBG("alloc mem type %d size %d\n", mtype, size);
22020 +
22021 + size = PAGE_ALIGN(size);
22022 + pages = size >> PAGE_SHIFT;
22023 +
22024 + mutex_lock(&region_mutex);
22025 +
22026 + r = _omap_vram_alloc(mtype, pages, paddr);
22027 +
22028 + mutex_unlock(&region_mutex);
22029 +
22030 + return r;
22031 +}
22032 +EXPORT_SYMBOL(omap_vram_alloc);
22033 +
22034 +void omap_vram_get_info(unsigned long *vram,
22035 + unsigned long *free_vram,
22036 + unsigned long *largest_free_block)
22037 +{
22038 + struct vram_region *vr;
22039 + struct vram_alloc *va;
22040 +
22041 + *vram = 0;
22042 + *free_vram = 0;
22043 + *largest_free_block = 0;
22044 +
22045 + mutex_lock(&region_mutex);
22046 +
22047 + list_for_each_entry(vr, &region_list, list) {
22048 + unsigned free;
22049 + unsigned long pa;
22050 +
22051 + pa = vr->paddr;
22052 + *vram += vr->pages << PAGE_SHIFT;
22053 +
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);
22060 + }
22061 +
22062 + free = vr->paddr + (vr->pages << PAGE_SHIFT) - pa;
22063 + *free_vram += free;
22064 + if (free > *largest_free_block)
22065 + *largest_free_block = free;
22066 + }
22067 +
22068 + mutex_unlock(&region_mutex);
22069 +}
22070 +EXPORT_SYMBOL(omap_vram_get_info);
22071 +
22072 +#if defined(CONFIG_DEBUG_FS)
22073 +static int vram_debug_show(struct seq_file *s, void *unused)
22074 +{
22075 + struct vram_region *vr;
22076 + struct vram_alloc *va;
22077 + unsigned size;
22078 +
22079 + mutex_lock(&region_mutex);
22080 +
22081 + list_for_each_entry(vr, &region_list, list) {
22082 + size = vr->pages << PAGE_SHIFT;
22083 + seq_printf(s, "%08lx-%08lx (%d bytes)\n",
22084 + vr->paddr, vr->paddr + size - 1,
22085 + size);
22086 +
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,
22091 + size);
22092 + }
22093 + }
22094 +
22095 + mutex_unlock(&region_mutex);
22096 +
22097 + return 0;
22098 +}
22099 +
22100 +static int vram_debug_open(struct inode *inode, struct file *file)
22101 +{
22102 + return single_open(file, vram_debug_show, inode->i_private);
22103 +}
22104 +
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,
22110 +};
22111 +
22112 +static int __init omap_vram_create_debugfs(void)
22113 +{
22114 + struct dentry *d;
22115 +
22116 + d = debugfs_create_file("vram", S_IRUGO, NULL,
22117 + NULL, &vram_debug_fops);
22118 + if (IS_ERR(d))
22119 + return PTR_ERR(d);
22120 +
22121 + return 0;
22122 +}
22123 +#endif
22124 +
22125 +static __init int omap_vram_init(void)
22126 +{
22127 + int i;
22128 +
22129 + vram_initialized = 1;
22130 +
22131 + for (i = 0; i < postponed_cnt; i++)
22132 + omap_vram_add_region(postponed_regions[i].paddr,
22133 + postponed_regions[i].size);
22134 +
22135 +#ifdef CONFIG_DEBUG_FS
22136 + if (omap_vram_create_debugfs())
22137 + pr_err("VRAM: Failed to create debugfs file\n");
22138 +#endif
22139 +
22140 + return 0;
22141 +}
22142 +
22143 +arch_initcall(omap_vram_init);
22144 +
22145 +/* boottime vram alloc stuff */
22146 +
22147 +/* set from board file */
22148 +static u32 omap_vram_sram_start __initdata;
22149 +static u32 omap_vram_sram_size __initdata;
22150 +
22151 +/* set from board file */
22152 +static u32 omap_vram_sdram_start __initdata;
22153 +static u32 omap_vram_sdram_size __initdata;
22154 +
22155 +/* set from kernel cmdline */
22156 +static u32 omap_vram_def_sdram_size __initdata;
22157 +static u32 omap_vram_def_sdram_start __initdata;
22158 +
22159 +static void __init omap_vram_early_vram(char **p)
22160 +{
22161 + omap_vram_def_sdram_size = memparse(*p, p);
22162 + if (**p == ',')
22163 + omap_vram_def_sdram_start = simple_strtoul((*p) + 1, p, 16);
22164 +}
22165 +__early_param("vram=", omap_vram_early_vram);
22166 +
22167 +/*
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.
22170 + */
22171 +void __init omap_vram_reserve_sdram(void)
22172 +{
22173 + struct bootmem_data *bdata;
22174 + unsigned long sdram_start, sdram_size;
22175 + u32 paddr;
22176 + u32 size = 0;
22177 +
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;
22182 + }
22183 +
22184 + if (!size) {
22185 + size = omap_vram_sdram_size;
22186 + paddr = omap_vram_sdram_start;
22187 + }
22188 +
22189 +#ifdef CONFIG_OMAP2_VRAM_SIZE
22190 + if (!size) {
22191 + size = CONFIG_OMAP2_VRAM_SIZE * 1024 * 1024;
22192 + paddr = 0;
22193 + }
22194 +#endif
22195 +
22196 + if (!size)
22197 + return;
22198 +
22199 + size = PAGE_ALIGN(size);
22200 +
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;
22204 +
22205 + if (paddr) {
22206 + if ((paddr & ~PAGE_MASK) || paddr < sdram_start ||
22207 + paddr + size > sdram_start + sdram_size) {
22208 + pr_err("Illegal SDRAM region for VRAM\n");
22209 + return;
22210 + }
22211 +
22212 + if (reserve_bootmem(paddr, size, BOOTMEM_EXCLUSIVE) < 0) {
22213 + pr_err("FB: failed to reserve VRAM\n");
22214 + return;
22215 + }
22216 + } else {
22217 + if (size > sdram_size) {
22218 + pr_err("Illegal SDRAM size for VRAM\n");
22219 + return;
22220 + }
22221 +
22222 + paddr = virt_to_phys(alloc_bootmem_pages(size));
22223 + BUG_ON(paddr & ~PAGE_MASK);
22224 + }
22225 +
22226 + omap_vram_add_region(paddr, size);
22227 +
22228 + pr_info("Reserving %u bytes SDRAM for VRAM\n", size);
22229 +}
22230 +
22231 +/*
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.
22236 + *
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.
22240 + */
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)
22246 +{
22247 + unsigned long pend_avail;
22248 + unsigned long reserved;
22249 + u32 paddr;
22250 + u32 size;
22251 +
22252 + paddr = omap_vram_sram_start;
22253 + size = omap_vram_sram_size;
22254 +
22255 + if (!size)
22256 + return 0;
22257 +
22258 + reserved = 0;
22259 + pend_avail = pstart_avail + size_avail;
22260 +
22261 + if (!paddr) {
22262 + /* Dynamic allocation */
22263 + if ((size_avail & PAGE_MASK) < size) {
22264 + pr_err("Not enough SRAM for VRAM\n");
22265 + return 0;
22266 + }
22267 + size_avail = (size_avail - size) & PAGE_MASK;
22268 + paddr = pstart_avail + size_avail;
22269 + }
22270 +
22271 + if (paddr < sram_pstart ||
22272 + paddr + size > sram_pstart + sram_size) {
22273 + pr_err("Illegal SRAM region for VRAM\n");
22274 + return 0;
22275 + }
22276 +
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;
22281 +
22282 + omap_vram_add_region(paddr, size);
22283 +
22284 + if (reserved)
22285 + pr_info("Reserving %lu bytes SRAM for VRAM\n", reserved);
22286 +
22287 + return reserved;
22288 +}
22289 +
22290 +void __init omap_vram_set_sdram_vram(u32 size, u32 start)
22291 +{
22292 + omap_vram_sdram_start = start;
22293 + omap_vram_sdram_size = size;
22294 +}
22295 +
22296 +void __init omap_vram_set_sram_vram(u32 size, u32 start)
22297 +{
22298 + omap_vram_sram_start = start;
22299 + omap_vram_sram_size = size;
22300 +}
22301 diff --git a/drivers/video/omap2/vrfb.c b/drivers/video/omap2/vrfb.c
22302 new file mode 100644
22303 index 0000000..8726689
22304 --- /dev/null
22305 +++ b/drivers/video/omap2/vrfb.c
22306 @@ -0,0 +1,277 @@
22307 +/*
22308 + * VRFB Rotation Engine
22309 + *
22310 + * Copyright (C) 2009 Nokia Corporation
22311 + * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
22312 + *
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.
22316 + *
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.
22321 + *
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.
22325 + */
22326 +
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>
22333 +
22334 +#include <mach/io.h>
22335 +#include <mach/vrfb.h>
22336 +#include <mach/sdrc.h>
22337 +/*#define DEBUG*/
22338 +
22339 +#ifdef DEBUG
22340 +#define DBG(format, ...) pr_debug("VRFB: " format, ## __VA_ARGS__)
22341 +#else
22342 +#define DBG(format, ...)
22343 +#endif
22344 +
22345 +#define SMS_ROT_VIRT_BASE(context, rot) \
22346 + (((context >= 4) ? 0xD0000000 : 0x70000000) \
22347 + + (0x4000000 * (context)) \
22348 + + (0x1000000 * (rot)))
22349 +
22350 +#define OMAP_VRFB_SIZE (2048 * 2048 * 4)
22351 +
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
22361 +
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;
22367 +
22368 +static DEFINE_MUTEX(ctx_lock);
22369 +
22370 +/*
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
22374 + * has finished.
22375 + */
22376 +static struct {
22377 + u32 physical_ba;
22378 + u32 control;
22379 + u32 size;
22380 +} vrfb_hw_context[VRFB_NUM_CTXS];
22381 +
22382 +static inline void restore_hw_context(int ctx)
22383 +{
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);
22387 +}
22388 +
22389 +void omap_vrfb_restore_context(void)
22390 +{
22391 + int i;
22392 + unsigned long map = ctx_map_active;
22393 +
22394 + for (i = ffs(map); i; i = ffs(map)) {
22395 + /* i=1..32 */
22396 + i--;
22397 + map &= ~(1 << i);
22398 + restore_hw_context(i);
22399 + }
22400 +}
22401 +
22402 +void omap_vrfb_adjust_size(u16 *width, u16 *height,
22403 + u8 bytespp)
22404 +{
22405 + *width = ALIGN(*width * bytespp, VRFB_PAGE_WIDTH) / bytespp;
22406 + *height = ALIGN(*height, VRFB_PAGE_HEIGHT);
22407 +}
22408 +EXPORT_SYMBOL(omap_vrfb_adjust_size);
22409 +
22410 +void omap_vrfb_setup(struct vrfb *vrfb, unsigned long paddr,
22411 + u16 width, u16 height,
22412 + unsigned bytespp, bool yuv_mode)
22413 +{
22414 + unsigned pixel_size_exp;
22415 + u16 vrfb_width;
22416 + u16 vrfb_height;
22417 + u8 ctx = vrfb->context;
22418 + u32 size;
22419 + u32 control;
22420 +
22421 + DBG("omapfb_set_vrfb(%d, %lx, %dx%d, %d)\n", ctx, paddr,
22422 + width, height, color_mode);
22423 +
22424 + /* For YUV2 and UYVY modes VRFB needs to handle pixels a bit
22425 + * differently. See TRM. */
22426 + if (yuv_mode) {
22427 + bytespp *= 2;
22428 + width /= 2;
22429 + }
22430 +
22431 + if (bytespp == 4)
22432 + pixel_size_exp = 2;
22433 + else if (bytespp == 2)
22434 + pixel_size_exp = 1;
22435 + else
22436 + BUG();
22437 +
22438 + vrfb_width = ALIGN(width * bytespp, VRFB_PAGE_WIDTH) / bytespp;
22439 + vrfb_height = ALIGN(height, VRFB_PAGE_HEIGHT);
22440 +
22441 + DBG("vrfb w %u, h %u bytespp %d\n", vrfb_width, vrfb_height, bytespp);
22442 +
22443 + size = vrfb_width << SMS_IMAGEWIDTH_OFFSET;
22444 + size |= vrfb_height << SMS_IMAGEHEIGHT_OFFSET;
22445 +
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;
22449 +
22450 + vrfb_hw_context[ctx].physical_ba = paddr;
22451 + vrfb_hw_context[ctx].size = size;
22452 + vrfb_hw_context[ctx].control = control;
22453 +
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);
22457 +
22458 + DBG("vrfb offset pixels %d, %d\n",
22459 + vrfb_width - width, vrfb_height - height);
22460 +
22461 + vrfb->xoffset = vrfb_width - width;
22462 + vrfb->yoffset = vrfb_height - height;
22463 + vrfb->bytespp = bytespp;
22464 +}
22465 +EXPORT_SYMBOL(omap_vrfb_setup);
22466 +
22467 +void omap_vrfb_release_ctx(struct vrfb *vrfb)
22468 +{
22469 + int rot;
22470 + int ctx = vrfb->context;
22471 +
22472 + if (ctx == 0xff)
22473 + return;
22474 +
22475 + DBG("release ctx %d\n", ctx);
22476 +
22477 + mutex_lock(&ctx_lock);
22478 +
22479 + BUG_ON(!(ctx_map & (1 << ctx)));
22480 +
22481 + clear_bit(ctx, &ctx_map_active);
22482 + clear_bit(ctx, &ctx_map);
22483 +
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;
22488 + }
22489 + }
22490 +
22491 + vrfb->context = 0xff;
22492 +
22493 + mutex_unlock(&ctx_lock);
22494 +}
22495 +EXPORT_SYMBOL(omap_vrfb_release_ctx);
22496 +
22497 +int omap_vrfb_request_ctx(struct vrfb *vrfb)
22498 +{
22499 + int rot;
22500 + u32 paddr;
22501 + u8 ctx;
22502 + int r;
22503 +
22504 + DBG("request ctx\n");
22505 +
22506 + mutex_lock(&ctx_lock);
22507 +
22508 + for (ctx = 0; ctx < VRFB_NUM_CTXS; ++ctx)
22509 + if ((ctx_map & (1 << ctx)) == 0)
22510 + break;
22511 +
22512 + if (ctx == VRFB_NUM_CTXS) {
22513 + pr_err("vrfb: no free contexts\n");
22514 + r = -EBUSY;
22515 + goto out;
22516 + }
22517 +
22518 + DBG("found free ctx %d\n", ctx);
22519 +
22520 + set_bit(ctx, &ctx_map);
22521 + WARN_ON(ctx_map_active & (1 << ctx));
22522 + set_bit(ctx, &ctx_map_active);
22523 +
22524 + memset(vrfb, 0, sizeof(*vrfb));
22525 +
22526 + vrfb->context = ctx;
22527 +
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",
22533 + ctx, rot * 90);
22534 + omap_vrfb_release_ctx(vrfb);
22535 + r = -ENOMEM;
22536 + goto out;
22537 + }
22538 +
22539 + vrfb->paddr[rot] = paddr;
22540 +
22541 + DBG("VRFB %d/%d: %lx\n", ctx, rot*90, vrfb->paddr[rot]);
22542 + }
22543 +
22544 + r = 0;
22545 +out:
22546 + mutex_unlock(&ctx_lock);
22547 + return r;
22548 +}
22549 +EXPORT_SYMBOL(omap_vrfb_request_ctx);
22550 +
22551 +void omap_vrfb_suspend_ctx(struct vrfb *vrfb)
22552 +{
22553 + DBG("suspend ctx %d\n", vrfb->context);
22554 + mutex_lock(&ctx_lock);
22555 +
22556 + BUG_ON(vrfb->context >= VRFB_NUM_CTXS);
22557 + BUG_ON(!((1 << vrfb->context) & ctx_map_active));
22558 +
22559 + clear_bit(vrfb->context, &ctx_map_active);
22560 + mutex_unlock(&ctx_lock);
22561 +}
22562 +EXPORT_SYMBOL(omap_vrfb_suspend_ctx);
22563 +
22564 +void omap_vrfb_resume_ctx(struct vrfb *vrfb)
22565 +{
22566 + DBG("resume ctx %d\n", vrfb->context);
22567 + mutex_lock(&ctx_lock);
22568 +
22569 + BUG_ON(vrfb->context >= VRFB_NUM_CTXS);
22570 + BUG_ON((1 << vrfb->context) & ctx_map_active);
22571 +
22572 + /*
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.
22577 + */
22578 + restore_hw_context(vrfb->context);
22579 + set_bit(vrfb->context, &ctx_map_active);
22580 + mutex_unlock(&ctx_lock);
22581 +}
22582 +EXPORT_SYMBOL(omap_vrfb_resume_ctx);
22583 +
22584 diff --git a/include/linux/omapfb.h b/include/linux/omapfb.h
22585 new file mode 100644
22586 index 0000000..52e0987
22587 --- /dev/null
22588 +++ b/include/linux/omapfb.h
22589 @@ -0,0 +1,242 @@
22590 +/*
22591 + * File: include/linux/omapfb.h
22592 + *
22593 + * Framebuffer driver for TI OMAP boards
22594 + *
22595 + * Copyright (C) 2004 Nokia Corporation
22596 + * Author: Imre Deak <imre.deak@nokia.com>
22597 + *
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.
22602 + *
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.
22607 + *
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.
22611 + */
22612 +
22613 +#ifndef __LINUX_OMAPFB_H__
22614 +#define __LINUX_OMAPFB_H__
22615 +
22616 +#include <linux/fb.h>
22617 +#include <linux/ioctl.h>
22618 +#include <linux/types.h>
22619 +
22620 +/* IOCTL commands. */
22621 +
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)
22626 +
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)
22648 +
22649 +#define OMAPFB_CAPS_GENERIC_MASK 0x00000fff
22650 +#define OMAPFB_CAPS_LCDC_MASK 0x00fff000
22651 +#define OMAPFB_CAPS_PANEL_MASK 0xff000000
22652 +
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
22662 +
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
22670 +
22671 +#define OMAPFB_MEMTYPE_SDRAM 0
22672 +#define OMAPFB_MEMTYPE_SRAM 1
22673 +#define OMAPFB_MEMTYPE_MAX 1
22674 +
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,
22685 +
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,
22692 +};
22693 +
22694 +struct omapfb_update_window {
22695 + __u32 x, y;
22696 + __u32 width, height;
22697 + __u32 format;
22698 + __u32 out_x, out_y;
22699 + __u32 out_width, out_height;
22700 + __u32 reserved[8];
22701 +};
22702 +
22703 +struct omapfb_update_window_old {
22704 + __u32 x, y;
22705 + __u32 width, height;
22706 + __u32 format;
22707 +};
22708 +
22709 +enum omapfb_plane {
22710 + OMAPFB_PLANE_GFX = 0,
22711 + OMAPFB_PLANE_VID1,
22712 + OMAPFB_PLANE_VID2,
22713 +};
22714 +
22715 +enum omapfb_channel_out {
22716 + OMAPFB_CHANNEL_OUT_LCD = 0,
22717 + OMAPFB_CHANNEL_OUT_DIGIT,
22718 +};
22719 +
22720 +struct omapfb_plane_info {
22721 + __u32 pos_x;
22722 + __u32 pos_y;
22723 + __u8 enabled;
22724 + __u8 channel_out;
22725 + __u8 mirror;
22726 + __u8 reserved1;
22727 + __u32 out_width;
22728 + __u32 out_height;
22729 + __u32 reserved2[12];
22730 +};
22731 +
22732 +struct omapfb_mem_info {
22733 + __u32 size;
22734 + __u8 type;
22735 + __u8 reserved[3];
22736 +};
22737 +
22738 +struct omapfb_caps {
22739 + __u32 ctrl;
22740 + __u32 plane_color;
22741 + __u32 wnd_color;
22742 +};
22743 +
22744 +enum omapfb_color_key_type {
22745 + OMAPFB_COLOR_KEY_DISABLED = 0,
22746 + OMAPFB_COLOR_KEY_GFX_DST,
22747 + OMAPFB_COLOR_KEY_VID_SRC,
22748 +};
22749 +
22750 +struct omapfb_color_key {
22751 + __u8 channel_out;
22752 + __u32 background;
22753 + __u32 trans_key;
22754 + __u8 key_type;
22755 +};
22756 +
22757 +enum omapfb_update_mode {
22758 + OMAPFB_UPDATE_DISABLED = 0,
22759 + OMAPFB_AUTO_UPDATE,
22760 + OMAPFB_MANUAL_UPDATE
22761 +};
22762 +
22763 +struct omapfb_memory_read {
22764 + __u16 x;
22765 + __u16 y;
22766 + __u16 w;
22767 + __u16 h;
22768 + size_t buffer_size;
22769 + void __user *buffer;
22770 +};
22771 +
22772 +struct omapfb_ovl_colormode {
22773 + __u8 overlay_idx;
22774 + __u8 mode_idx;
22775 + __u32 bits_per_pixel;
22776 + __u32 nonstd;
22777 + struct fb_bitfield red;
22778 + struct fb_bitfield green;
22779 + struct fb_bitfield blue;
22780 + struct fb_bitfield transp;
22781 +};
22782 +
22783 +struct omapfb_vram_info {
22784 + __u32 total;
22785 + __u32 free;
22786 + __u32 largest_free_block;
22787 + __u32 reserved[5];
22788 +};
22789 +
22790 +#ifdef __KERNEL__
22791 +
22792 +#include <mach/board.h>
22793 +
22794 +#ifdef CONFIG_ARCH_OMAP1
22795 +#define OMAPFB_PLANE_NUM 1
22796 +#else
22797 +#define OMAPFB_PLANE_NUM 3
22798 +#endif
22799 +
22800 +struct omapfb_mem_region {
22801 + u32 paddr;
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
22809 + */
22810 + unsigned alloc:1; /* allocated by the driver */
22811 + unsigned map:1; /* kernel mapped by the driver */
22812 +};
22813 +
22814 +struct omapfb_mem_desc {
22815 + int region_cnt;
22816 + struct omapfb_mem_region region[OMAPFB_PLANE_NUM];
22817 +};
22818 +
22819 +struct omapfb_platform_data {
22820 + struct omap_lcd_config lcd;
22821 + struct omapfb_mem_desc mem_desc;
22822 + void *ctrl_platform_data;
22823 +};
22824 +
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);
22828 +
22829 +#endif
22830 +
22831 +#endif /* __OMAPFB_H */
This page took 1.21872 seconds and 3 git commands to generate.