mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-04 09:34:12 +08:00
Merge branch 'for-linus' of git://gitorious.org/linux-omap-dss2/linux
* 'for-linus' of git://gitorious.org/linux-omap-dss2/linux: MAINTAINERS: Add OMAP2/3 DSS and OMAPFB maintainer OMAP: SDP: Enable DSS2 for OMAP3 SDP board OMAP: DSS2: Taal DSI command mode panel driver OMAP: DSS2: Add generic and Sharp panel drivers OMAP: DSS2: omapfb driver OMAP: DSS2: DSI driver OMAP: DSS2: SDI driver OMAP: DSS2: RFBI driver OMAP: DSS2: Video encoder driver OMAP: DSS2: DPI driver OMAP: DSS2: DISPC OMAP: DSS2: Add more core files OMAP: DSS2: Display Subsystem Driver core OMAP: DSS2: Documentation for DSS2 OMAP: Add support for VRFB rotation engine OMAP: Add VRAM manager OMAP: OMAPFB: add omapdss device OMAP: OMAPFB: split omapfb.h OMAP2: Add funcs for writing SMS_ROT_* registers
This commit is contained in:
commit
aa2cf42059
317
Documentation/arm/OMAP/DSS
Normal file
317
Documentation/arm/OMAP/DSS
Normal file
@ -0,0 +1,317 @@
|
||||
OMAP2/3 Display Subsystem
|
||||
-------------------------
|
||||
|
||||
This is an almost total rewrite of the OMAP FB driver in drivers/video/omap
|
||||
(let's call it DSS1). The main differences between DSS1 and DSS2 are DSI,
|
||||
TV-out and multiple display support, but there are lots of small improvements
|
||||
also.
|
||||
|
||||
The DSS2 driver (omapdss module) is in arch/arm/plat-omap/dss/, and the FB,
|
||||
panel and controller drivers are in drivers/video/omap2/. DSS1 and DSS2 live
|
||||
currently side by side, you can choose which one to use.
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
Working and tested features include:
|
||||
|
||||
- MIPI DPI (parallel) output
|
||||
- MIPI DSI output in command mode
|
||||
- MIPI DBI (RFBI) output
|
||||
- SDI output
|
||||
- TV output
|
||||
- All pieces can be compiled as a module or inside kernel
|
||||
- Use DISPC to update any of the outputs
|
||||
- Use CPU to update RFBI or DSI output
|
||||
- OMAP DISPC planes
|
||||
- RGB16, RGB24 packed, RGB24 unpacked
|
||||
- YUV2, UYVY
|
||||
- Scaling
|
||||
- Adjusting DSS FCK to find a good pixel clock
|
||||
- Use DSI DPLL to create DSS FCK
|
||||
|
||||
Tested boards include:
|
||||
- OMAP3 SDP board
|
||||
- Beagle board
|
||||
- N810
|
||||
|
||||
omapdss driver
|
||||
--------------
|
||||
|
||||
The DSS driver does not itself have any support for Linux framebuffer, V4L or
|
||||
such like the current ones, but it has an internal kernel API that upper level
|
||||
drivers can use.
|
||||
|
||||
The DSS driver models OMAP's overlays, overlay managers and displays in a
|
||||
flexible way to enable non-common multi-display configuration. In addition to
|
||||
modelling the hardware overlays, omapdss supports virtual overlays and overlay
|
||||
managers. These can be used when updating a display with CPU or system DMA.
|
||||
|
||||
Panel and controller drivers
|
||||
----------------------------
|
||||
|
||||
The drivers implement panel or controller specific functionality and are not
|
||||
usually visible to users except through omapfb driver. They register
|
||||
themselves to the DSS driver.
|
||||
|
||||
omapfb driver
|
||||
-------------
|
||||
|
||||
The omapfb driver implements arbitrary number of standard linux framebuffers.
|
||||
These framebuffers can be routed flexibly to any overlays, thus allowing very
|
||||
dynamic display architecture.
|
||||
|
||||
The driver exports some omapfb specific ioctls, which are compatible with the
|
||||
ioctls in the old driver.
|
||||
|
||||
The rest of the non standard features are exported via sysfs. Whether the final
|
||||
implementation will use sysfs, or ioctls, is still open.
|
||||
|
||||
V4L2 drivers
|
||||
------------
|
||||
|
||||
V4L2 is being implemented in TI.
|
||||
|
||||
From omapdss point of view the V4L2 drivers should be similar to framebuffer
|
||||
driver.
|
||||
|
||||
Architecture
|
||||
--------------------
|
||||
|
||||
Some clarification what the different components do:
|
||||
|
||||
- Framebuffer is a memory area inside OMAP's SRAM/SDRAM that contains the
|
||||
pixel data for the image. Framebuffer has width and height and color
|
||||
depth.
|
||||
- Overlay defines where the pixels are read from and where they go on the
|
||||
screen. The overlay may be smaller than framebuffer, thus displaying only
|
||||
part of the framebuffer. The position of the overlay may be changed if
|
||||
the overlay is smaller than the display.
|
||||
- Overlay manager combines the overlays in to one image and feeds them to
|
||||
display.
|
||||
- Display is the actual physical display device.
|
||||
|
||||
A framebuffer can be connected to multiple overlays to show the same pixel data
|
||||
on all of the overlays. Note that in this case the overlay input sizes must be
|
||||
the same, but, in case of video overlays, the output size can be different. Any
|
||||
framebuffer can be connected to any overlay.
|
||||
|
||||
An overlay can be connected to one overlay manager. Also DISPC overlays can be
|
||||
connected only to DISPC overlay managers, and virtual overlays can be only
|
||||
connected to virtual overlays.
|
||||
|
||||
An overlay manager can be connected to one display. There are certain
|
||||
restrictions which kinds of displays an overlay manager can be connected:
|
||||
|
||||
- DISPC TV overlay manager can be only connected to TV display.
|
||||
- Virtual overlay managers can only be connected to DBI or DSI displays.
|
||||
- DISPC LCD overlay manager can be connected to all displays, except TV
|
||||
display.
|
||||
|
||||
Sysfs
|
||||
-----
|
||||
The sysfs interface is mainly used for testing. I don't think sysfs
|
||||
interface is the best for this in the final version, but I don't quite know
|
||||
what would be the best interfaces for these things.
|
||||
|
||||
The sysfs interface is divided to two parts: DSS and FB.
|
||||
|
||||
/sys/class/graphics/fb? directory:
|
||||
mirror 0=off, 1=on
|
||||
rotate Rotation 0-3 for 0, 90, 180, 270 degrees
|
||||
rotate_type 0 = DMA rotation, 1 = VRFB rotation
|
||||
overlays List of overlay numbers to which framebuffer pixels go
|
||||
phys_addr Physical address of the framebuffer
|
||||
virt_addr Virtual address of the framebuffer
|
||||
size Size of the framebuffer
|
||||
|
||||
/sys/devices/platform/omapdss/overlay? directory:
|
||||
enabled 0=off, 1=on
|
||||
input_size width,height (ie. the framebuffer size)
|
||||
manager Destination overlay manager name
|
||||
name
|
||||
output_size width,height
|
||||
position x,y
|
||||
screen_width width
|
||||
global_alpha global alpha 0-255 0=transparent 255=opaque
|
||||
|
||||
/sys/devices/platform/omapdss/manager? directory:
|
||||
display Destination display
|
||||
name
|
||||
alpha_blending_enabled 0=off, 1=on
|
||||
trans_key_enabled 0=off, 1=on
|
||||
trans_key_type gfx-destination, video-source
|
||||
trans_key_value transparency color key (RGB24)
|
||||
default_color default background color (RGB24)
|
||||
|
||||
/sys/devices/platform/omapdss/display? directory:
|
||||
ctrl_name Controller name
|
||||
mirror 0=off, 1=on
|
||||
update_mode 0=off, 1=auto, 2=manual
|
||||
enabled 0=off, 1=on
|
||||
name
|
||||
rotate Rotation 0-3 for 0, 90, 180, 270 degrees
|
||||
timings Display timings (pixclock,xres/hfp/hbp/hsw,yres/vfp/vbp/vsw)
|
||||
When writing, two special timings are accepted for tv-out:
|
||||
"pal" and "ntsc"
|
||||
panel_name
|
||||
tear_elim Tearing elimination 0=off, 1=on
|
||||
|
||||
There are also some debugfs files at <debugfs>/omapdss/ which show information
|
||||
about clocks and registers.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
The following definitions have been made for the examples below:
|
||||
|
||||
ovl0=/sys/devices/platform/omapdss/overlay0
|
||||
ovl1=/sys/devices/platform/omapdss/overlay1
|
||||
ovl2=/sys/devices/platform/omapdss/overlay2
|
||||
|
||||
mgr0=/sys/devices/platform/omapdss/manager0
|
||||
mgr1=/sys/devices/platform/omapdss/manager1
|
||||
|
||||
lcd=/sys/devices/platform/omapdss/display0
|
||||
dvi=/sys/devices/platform/omapdss/display1
|
||||
tv=/sys/devices/platform/omapdss/display2
|
||||
|
||||
fb0=/sys/class/graphics/fb0
|
||||
fb1=/sys/class/graphics/fb1
|
||||
fb2=/sys/class/graphics/fb2
|
||||
|
||||
Default setup on OMAP3 SDP
|
||||
--------------------------
|
||||
|
||||
Here's the default setup on OMAP3 SDP board. All planes go to LCD. DVI
|
||||
and TV-out are not in use. The columns from left to right are:
|
||||
framebuffers, overlays, overlay managers, displays. Framebuffers are
|
||||
handled by omapfb, and the rest by the DSS.
|
||||
|
||||
FB0 --- GFX -\ DVI
|
||||
FB1 --- VID1 --+- LCD ---- LCD
|
||||
FB2 --- VID2 -/ TV ----- TV
|
||||
|
||||
Example: Switch from LCD to DVI
|
||||
----------------------
|
||||
|
||||
w=`cat $dvi/timings | cut -d "," -f 2 | cut -d "/" -f 1`
|
||||
h=`cat $dvi/timings | cut -d "," -f 3 | cut -d "/" -f 1`
|
||||
|
||||
echo "0" > $lcd/enabled
|
||||
echo "" > $mgr0/display
|
||||
fbset -fb /dev/fb0 -xres $w -yres $h -vxres $w -vyres $h
|
||||
# at this point you have to switch the dvi/lcd dip-switch from the omap board
|
||||
echo "dvi" > $mgr0/display
|
||||
echo "1" > $dvi/enabled
|
||||
|
||||
After this the configuration looks like:
|
||||
|
||||
FB0 --- GFX -\ -- DVI
|
||||
FB1 --- VID1 --+- LCD -/ LCD
|
||||
FB2 --- VID2 -/ TV ----- TV
|
||||
|
||||
Example: Clone GFX overlay to LCD and TV
|
||||
-------------------------------
|
||||
|
||||
w=`cat $tv/timings | cut -d "," -f 2 | cut -d "/" -f 1`
|
||||
h=`cat $tv/timings | cut -d "," -f 3 | cut -d "/" -f 1`
|
||||
|
||||
echo "0" > $ovl0/enabled
|
||||
echo "0" > $ovl1/enabled
|
||||
|
||||
echo "" > $fb1/overlays
|
||||
echo "0,1" > $fb0/overlays
|
||||
|
||||
echo "$w,$h" > $ovl1/output_size
|
||||
echo "tv" > $ovl1/manager
|
||||
|
||||
echo "1" > $ovl0/enabled
|
||||
echo "1" > $ovl1/enabled
|
||||
|
||||
echo "1" > $tv/enabled
|
||||
|
||||
After this the configuration looks like (only relevant parts shown):
|
||||
|
||||
FB0 +-- GFX ---- LCD ---- LCD
|
||||
\- VID1 ---- TV ---- TV
|
||||
|
||||
Misc notes
|
||||
----------
|
||||
|
||||
OMAP FB allocates the framebuffer memory using the OMAP VRAM allocator.
|
||||
|
||||
Using DSI DPLL to generate pixel clock it is possible produce the pixel clock
|
||||
of 86.5MHz (max possible), and with that you get 1280x1024@57 output from DVI.
|
||||
|
||||
Rotation and mirroring currently only supports RGB565 and RGB8888 modes. VRFB
|
||||
does not support mirroring.
|
||||
|
||||
VRFB rotation requires much more memory than non-rotated framebuffer, so you
|
||||
probably need to increase your vram setting before using VRFB rotation. Also,
|
||||
many applications may not work with VRFB if they do not pay attention to all
|
||||
framebuffer parameters.
|
||||
|
||||
Kernel boot arguments
|
||||
---------------------
|
||||
|
||||
vram=<size>
|
||||
- Amount of total VRAM to preallocate. For example, "10M". omapfb
|
||||
allocates memory for framebuffers from VRAM.
|
||||
|
||||
omapfb.mode=<display>:<mode>[,...]
|
||||
- Default video mode for specified displays. For example,
|
||||
"dvi:800x400MR-24@60". See drivers/video/modedb.c.
|
||||
There are also two special modes: "pal" and "ntsc" that
|
||||
can be used to tv out.
|
||||
|
||||
omapfb.vram=<fbnum>:<size>[@<physaddr>][,...]
|
||||
- VRAM allocated for a framebuffer. Normally omapfb allocates vram
|
||||
depending on the display size. With this you can manually allocate
|
||||
more or define the physical address of each framebuffer. For example,
|
||||
"1:4M" to allocate 4M for fb1.
|
||||
|
||||
omapfb.debug=<y|n>
|
||||
- Enable debug printing. You have to have OMAPFB debug support enabled
|
||||
in kernel config.
|
||||
|
||||
omapfb.test=<y|n>
|
||||
- Draw test pattern to framebuffer whenever framebuffer settings change.
|
||||
You need to have OMAPFB debug support enabled in kernel config.
|
||||
|
||||
omapfb.vrfb=<y|n>
|
||||
- Use VRFB rotation for all framebuffers.
|
||||
|
||||
omapfb.rotate=<angle>
|
||||
- Default rotation applied to all framebuffers.
|
||||
0 - 0 degree rotation
|
||||
1 - 90 degree rotation
|
||||
2 - 180 degree rotation
|
||||
3 - 270 degree rotation
|
||||
|
||||
omapfb.mirror=<y|n>
|
||||
- Default mirror for all framebuffers. Only works with DMA rotation.
|
||||
|
||||
omapdss.def_disp=<display>
|
||||
- Name of default display, to which all overlays will be connected.
|
||||
Common examples are "lcd" or "tv".
|
||||
|
||||
omapdss.debug=<y|n>
|
||||
- Enable debug printing. You have to have DSS debug support enabled in
|
||||
kernel config.
|
||||
|
||||
TODO
|
||||
----
|
||||
|
||||
DSS locking
|
||||
|
||||
Error checking
|
||||
- Lots of checks are missing or implemented just as BUG()
|
||||
|
||||
System DMA update for DSI
|
||||
- Can be used for RGB16 and RGB24P modes. Probably not for RGB24U (how
|
||||
to skip the empty byte?)
|
||||
|
||||
OMAP1 support
|
||||
- Not sure if needed
|
||||
|
17
MAINTAINERS
17
MAINTAINERS
@ -3903,6 +3903,23 @@ L: linux-omap@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/video/omap/
|
||||
|
||||
OMAP DISPLAY SUBSYSTEM SUPPORT (DSS2)
|
||||
M: Tomi Valkeinen <tomi.valkeinen@nokia.com>
|
||||
L: linux-omap@vger.kernel.org
|
||||
L: linux-fbdev@vger.kernel.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
F: drivers/video/omap2/dss/
|
||||
F: drivers/video/omap2/vrfb.c
|
||||
F: drivers/video/omap2/vram.c
|
||||
F: Documentation/arm/OMAP/DSS
|
||||
|
||||
OMAP FRAMEBUFFER SUPPORT (FOR DSS2)
|
||||
M: Tomi Valkeinen <tomi.valkeinen@nokia.com>
|
||||
L: linux-omap@vger.kernel.org
|
||||
L: linux-fbdev@vger.kernel.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
F: drivers/video/omap2/omapfb/
|
||||
|
||||
OMAP MMC SUPPORT
|
||||
M: Jarkko Lavinen <jarkko.lavinen@nokia.com>
|
||||
L: linux-omap@vger.kernel.org
|
||||
|
@ -963,10 +963,32 @@ CONFIG_FB_CFB_IMAGEBLIT=y
|
||||
#
|
||||
# CONFIG_FB_S1D13XXX is not set
|
||||
# CONFIG_FB_VIRTUAL is not set
|
||||
CONFIG_FB_OMAP=y
|
||||
# CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
|
||||
# CONFIG_FB_METRONOME is not set
|
||||
# CONFIG_FB_MB862XX is not set
|
||||
# CONFIG_FB_BROADSHEET is not set
|
||||
# CONFIG_FB_OMAP_LCD_VGA is not set
|
||||
# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
|
||||
CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=2
|
||||
CONFIG_OMAP2_VRAM=y
|
||||
CONFIG_OMAP2_VRFB=y
|
||||
CONFIG_OMAP2_DSS=y
|
||||
CONFIG_OMAP2_VRAM_SIZE=4
|
||||
CONFIG_OMAP2_DSS_DEBUG_SUPPORT=y
|
||||
# CONFIG_OMAP2_DSS_RFBI is not set
|
||||
CONFIG_OMAP2_DSS_VENC=y
|
||||
# CONFIG_OMAP2_DSS_SDI is not set
|
||||
# CONFIG_OMAP2_DSS_DSI is not set
|
||||
# CONFIG_OMAP2_DSS_FAKE_VSYNC is not set
|
||||
CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK=0
|
||||
CONFIG_FB_OMAP2=y
|
||||
CONFIG_FB_OMAP2_DEBUG_SUPPORT=y
|
||||
# CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE is not set
|
||||
CONFIG_FB_OMAP2_NUM_FBS=3
|
||||
|
||||
#
|
||||
# OMAP2/3 Display Device Drivers
|
||||
#
|
||||
CONFIG_PANEL_GENERIC=y
|
||||
CONFIG_PANEL_SHARP_LS037V7DW01=y
|
||||
# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
|
||||
|
||||
#
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/omapfb.h>
|
||||
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/ads7846.h>
|
||||
@ -32,7 +33,6 @@
|
||||
#include <plat/keypad.h>
|
||||
#include <plat/common.h>
|
||||
#include <plat/dsp_common.h>
|
||||
#include <plat/omapfb.h>
|
||||
#include <plat/hwa742.h>
|
||||
#include <plat/lcd_mipid.h>
|
||||
#include <plat/mmc.h>
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include <plat/common.h>
|
||||
#include <plat/dma.h>
|
||||
#include <plat/gpmc.h>
|
||||
#include <plat/display.h>
|
||||
|
||||
#include <plat/control.h>
|
||||
#include <plat/gpmc-smc91x.h>
|
||||
@ -152,31 +153,152 @@ static struct spi_board_info sdp3430_spi_board_info[] __initdata = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device sdp3430_lcd_device = {
|
||||
.name = "sdp2430_lcd",
|
||||
|
||||
#define SDP3430_LCD_PANEL_BACKLIGHT_GPIO 8
|
||||
#define SDP3430_LCD_PANEL_ENABLE_GPIO 5
|
||||
|
||||
static unsigned backlight_gpio;
|
||||
static unsigned enable_gpio;
|
||||
static int lcd_enabled;
|
||||
static int dvi_enabled;
|
||||
|
||||
static void __init sdp3430_display_init(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
enable_gpio = SDP3430_LCD_PANEL_ENABLE_GPIO;
|
||||
backlight_gpio = SDP3430_LCD_PANEL_BACKLIGHT_GPIO;
|
||||
|
||||
r = gpio_request(enable_gpio, "LCD reset");
|
||||
if (r) {
|
||||
printk(KERN_ERR "failed to get LCD reset GPIO\n");
|
||||
goto err0;
|
||||
}
|
||||
|
||||
r = gpio_request(backlight_gpio, "LCD Backlight");
|
||||
if (r) {
|
||||
printk(KERN_ERR "failed to get LCD backlight GPIO\n");
|
||||
goto err1;
|
||||
}
|
||||
|
||||
gpio_direction_output(enable_gpio, 0);
|
||||
gpio_direction_output(backlight_gpio, 0);
|
||||
|
||||
return;
|
||||
err1:
|
||||
gpio_free(enable_gpio);
|
||||
err0:
|
||||
return;
|
||||
}
|
||||
|
||||
static int sdp3430_panel_enable_lcd(struct omap_dss_device *dssdev)
|
||||
{
|
||||
if (dvi_enabled) {
|
||||
printk(KERN_ERR "cannot enable LCD, DVI is enabled\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
gpio_direction_output(enable_gpio, 1);
|
||||
gpio_direction_output(backlight_gpio, 1);
|
||||
|
||||
lcd_enabled = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sdp3430_panel_disable_lcd(struct omap_dss_device *dssdev)
|
||||
{
|
||||
lcd_enabled = 0;
|
||||
|
||||
gpio_direction_output(enable_gpio, 0);
|
||||
gpio_direction_output(backlight_gpio, 0);
|
||||
}
|
||||
|
||||
static int sdp3430_panel_enable_dvi(struct omap_dss_device *dssdev)
|
||||
{
|
||||
if (lcd_enabled) {
|
||||
printk(KERN_ERR "cannot enable DVI, LCD is enabled\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dvi_enabled = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sdp3430_panel_disable_dvi(struct omap_dss_device *dssdev)
|
||||
{
|
||||
dvi_enabled = 0;
|
||||
}
|
||||
|
||||
static int sdp3430_panel_enable_tv(struct omap_dss_device *dssdev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sdp3430_panel_disable_tv(struct omap_dss_device *dssdev)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static struct omap_dss_device sdp3430_lcd_device = {
|
||||
.name = "lcd",
|
||||
.driver_name = "sharp_ls_panel",
|
||||
.type = OMAP_DISPLAY_TYPE_DPI,
|
||||
.phy.dpi.data_lines = 16,
|
||||
.platform_enable = sdp3430_panel_enable_lcd,
|
||||
.platform_disable = sdp3430_panel_disable_lcd,
|
||||
};
|
||||
|
||||
static struct omap_dss_device sdp3430_dvi_device = {
|
||||
.name = "dvi",
|
||||
.driver_name = "generic_panel",
|
||||
.type = OMAP_DISPLAY_TYPE_DPI,
|
||||
.phy.dpi.data_lines = 24,
|
||||
.platform_enable = sdp3430_panel_enable_dvi,
|
||||
.platform_disable = sdp3430_panel_disable_dvi,
|
||||
};
|
||||
|
||||
static struct omap_dss_device sdp3430_tv_device = {
|
||||
.name = "tv",
|
||||
.driver_name = "venc",
|
||||
.type = OMAP_DISPLAY_TYPE_VENC,
|
||||
.phy.venc.type = OMAP_DSS_VENC_TYPE_SVIDEO,
|
||||
.platform_enable = sdp3430_panel_enable_tv,
|
||||
.platform_disable = sdp3430_panel_disable_tv,
|
||||
};
|
||||
|
||||
|
||||
static struct omap_dss_device *sdp3430_dss_devices[] = {
|
||||
&sdp3430_lcd_device,
|
||||
&sdp3430_dvi_device,
|
||||
&sdp3430_tv_device,
|
||||
};
|
||||
|
||||
static struct omap_dss_board_info sdp3430_dss_data = {
|
||||
.num_devices = ARRAY_SIZE(sdp3430_dss_devices),
|
||||
.devices = sdp3430_dss_devices,
|
||||
.default_device = &sdp3430_lcd_device,
|
||||
};
|
||||
|
||||
static struct platform_device sdp3430_dss_device = {
|
||||
.name = "omapdss",
|
||||
.id = -1,
|
||||
.dev = {
|
||||
.platform_data = &sdp3430_dss_data,
|
||||
},
|
||||
};
|
||||
|
||||
static struct regulator_consumer_supply sdp3430_vdac_supply = {
|
||||
.supply = "vdac",
|
||||
.dev = &sdp3430_lcd_device.dev,
|
||||
};
|
||||
|
||||
static struct regulator_consumer_supply sdp3430_vdvi_supply = {
|
||||
.supply = "vdvi",
|
||||
.dev = &sdp3430_lcd_device.dev,
|
||||
static struct regulator_consumer_supply sdp3430_vdda_dac_supply = {
|
||||
.supply = "vdda_dac",
|
||||
.dev = &sdp3430_dss_device.dev,
|
||||
};
|
||||
|
||||
static struct platform_device *sdp3430_devices[] __initdata = {
|
||||
&sdp3430_lcd_device,
|
||||
};
|
||||
|
||||
static struct omap_lcd_config sdp3430_lcd_config __initdata = {
|
||||
.ctrl_name = "internal",
|
||||
&sdp3430_dss_device,
|
||||
};
|
||||
|
||||
static struct omap_board_config_kernel sdp3430_config[] __initdata = {
|
||||
{ OMAP_TAG_LCD, &sdp3430_lcd_config },
|
||||
};
|
||||
|
||||
static void __init omap_3430sdp_init_irq(void)
|
||||
@ -392,22 +514,34 @@ static struct regulator_init_data sdp3430_vdac = {
|
||||
| REGULATOR_CHANGE_STATUS,
|
||||
},
|
||||
.num_consumer_supplies = 1,
|
||||
.consumer_supplies = &sdp3430_vdac_supply,
|
||||
.consumer_supplies = &sdp3430_vdda_dac_supply,
|
||||
};
|
||||
|
||||
/* VPLL2 for digital video outputs */
|
||||
static struct regulator_consumer_supply sdp3430_vpll2_supplies[] = {
|
||||
{
|
||||
.supply = "vdvi",
|
||||
.dev = &sdp3430_lcd_device.dev,
|
||||
},
|
||||
{
|
||||
.supply = "vdds_dsi",
|
||||
.dev = &sdp3430_dss_device.dev,
|
||||
}
|
||||
};
|
||||
|
||||
static struct regulator_init_data sdp3430_vpll2 = {
|
||||
.constraints = {
|
||||
.name = "VDVI",
|
||||
.min_uV = 1800000,
|
||||
.max_uV = 1800000,
|
||||
.apply_uV = true,
|
||||
.valid_modes_mask = REGULATOR_MODE_NORMAL
|
||||
| REGULATOR_MODE_STANDBY,
|
||||
.valid_ops_mask = REGULATOR_CHANGE_MODE
|
||||
| REGULATOR_CHANGE_STATUS,
|
||||
},
|
||||
.num_consumer_supplies = 1,
|
||||
.consumer_supplies = &sdp3430_vdvi_supply,
|
||||
.num_consumer_supplies = ARRAY_SIZE(sdp3430_vpll2_supplies),
|
||||
.consumer_supplies = sdp3430_vpll2_supplies,
|
||||
};
|
||||
|
||||
static struct twl4030_codec_audio_data sdp3430_audio = {
|
||||
@ -521,6 +655,7 @@ static void __init omap_3430sdp_init(void)
|
||||
omap_serial_init();
|
||||
usb_musb_init();
|
||||
board_smc91x_init();
|
||||
sdp3430_display_init();
|
||||
enable_board_wakeup_source();
|
||||
usb_ehci_init(&ehci_pdata);
|
||||
}
|
||||
|
@ -116,10 +116,10 @@ static struct omap_clk omap24xx_clks[] = {
|
||||
CLK(NULL, "mdm_ick", &mdm_ick, CK_243X),
|
||||
CLK(NULL, "mdm_osc_ck", &mdm_osc_ck, CK_243X),
|
||||
/* DSS domain clocks */
|
||||
CLK("omapfb", "ick", &dss_ick, CK_243X | CK_242X),
|
||||
CLK("omapfb", "dss1_fck", &dss1_fck, CK_243X | CK_242X),
|
||||
CLK("omapfb", "dss2_fck", &dss2_fck, CK_243X | CK_242X),
|
||||
CLK("omapfb", "tv_fck", &dss_54m_fck, CK_243X | CK_242X),
|
||||
CLK("omapdss", "ick", &dss_ick, CK_243X | CK_242X),
|
||||
CLK("omapdss", "dss1_fck", &dss1_fck, CK_243X | CK_242X),
|
||||
CLK("omapdss", "dss2_fck", &dss2_fck, CK_243X | CK_242X),
|
||||
CLK("omapdss", "tv_fck", &dss_54m_fck, CK_243X | CK_242X),
|
||||
/* L3 domain clocks */
|
||||
CLK(NULL, "core_l3_ck", &core_l3_ck, CK_243X | CK_242X),
|
||||
CLK(NULL, "ssi_fck", &ssi_ssr_sst_fck, CK_243X | CK_242X),
|
||||
|
@ -236,13 +236,13 @@ static struct omap_clk omap34xx_clks[] = {
|
||||
CLK("omap_rng", "ick", &rng_ick, CK_343X),
|
||||
CLK(NULL, "sha11_ick", &sha11_ick, CK_343X),
|
||||
CLK(NULL, "des1_ick", &des1_ick, CK_343X),
|
||||
CLK("omapfb", "dss1_fck", &dss1_alwon_fck_3430es1, CK_3430ES1),
|
||||
CLK("omapfb", "dss1_fck", &dss1_alwon_fck_3430es2, CK_3430ES2),
|
||||
CLK("omapfb", "tv_fck", &dss_tv_fck, CK_343X),
|
||||
CLK("omapfb", "video_fck", &dss_96m_fck, CK_343X),
|
||||
CLK("omapfb", "dss2_fck", &dss2_alwon_fck, CK_343X),
|
||||
CLK("omapfb", "ick", &dss_ick_3430es1, CK_3430ES1),
|
||||
CLK("omapfb", "ick", &dss_ick_3430es2, CK_3430ES2),
|
||||
CLK("omapdss", "dss1_fck", &dss1_alwon_fck_3430es1, CK_3430ES1),
|
||||
CLK("omapdss", "dss1_fck", &dss1_alwon_fck_3430es2, CK_3430ES2),
|
||||
CLK("omapdss", "tv_fck", &dss_tv_fck, CK_343X),
|
||||
CLK("omapdss", "video_fck", &dss_96m_fck, CK_343X),
|
||||
CLK("omapdss", "dss2_fck", &dss2_alwon_fck, CK_343X),
|
||||
CLK("omapdss", "ick", &dss_ick_3430es1, CK_3430ES1),
|
||||
CLK("omapdss", "ick", &dss_ick_3430es2, CK_3430ES2),
|
||||
CLK(NULL, "cam_mclk", &cam_mclk, CK_343X),
|
||||
CLK(NULL, "cam_ick", &cam_ick, CK_343X),
|
||||
CLK(NULL, "csi2_96m_fck", &csi2_96m_fck, CK_343X),
|
||||
|
@ -22,17 +22,18 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/omapfb.h>
|
||||
|
||||
#include <asm/tlb.h>
|
||||
|
||||
#include <asm/mach/map.h>
|
||||
|
||||
#include <plat/mux.h>
|
||||
#include <plat/omapfb.h>
|
||||
#include <plat/sram.h>
|
||||
#include <plat/sdrc.h>
|
||||
#include <plat/gpmc.h>
|
||||
#include <plat/serial.h>
|
||||
#include <plat/vram.h>
|
||||
|
||||
#ifndef CONFIG_ARCH_OMAP4 /* FIXME: Remove this once clkdev is ready */
|
||||
#include "clock.h"
|
||||
@ -264,6 +265,7 @@ void __init omap2_map_common_io(void)
|
||||
omap2_check_revision();
|
||||
omap_sram_init();
|
||||
omapfb_reserve_sdram();
|
||||
omap_vram_reserve_sdram();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -160,3 +160,19 @@ void __init omap2_sdrc_init(struct omap_sdrc_params *sdrc_cs0,
|
||||
sdrc_write_reg(l, SDRC_POWER);
|
||||
omap2_sms_save_context();
|
||||
}
|
||||
|
||||
void omap2_sms_write_rot_control(u32 val, unsigned ctx)
|
||||
{
|
||||
sms_write_reg(val, SMS_ROT_CONTROL(ctx));
|
||||
}
|
||||
|
||||
void omap2_sms_write_rot_size(u32 val, unsigned ctx)
|
||||
{
|
||||
sms_write_reg(val, SMS_ROT_SIZE(ctx));
|
||||
}
|
||||
|
||||
void omap2_sms_write_rot_physical_ba(u32 val, unsigned ctx)
|
||||
{
|
||||
sms_write_reg(val, SMS_ROT_PHYSICAL_BA(ctx));
|
||||
}
|
||||
|
||||
|
@ -28,13 +28,13 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/bootmem.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/omapfb.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <asm/mach/map.h>
|
||||
|
||||
#include <plat/board.h>
|
||||
#include <plat/sram.h>
|
||||
#include <plat/omapfb.h>
|
||||
|
||||
#if defined(CONFIG_FB_OMAP) || defined(CONFIG_FB_OMAP_MODULE)
|
||||
|
||||
@ -55,6 +55,10 @@ static struct platform_device omap_fb_device = {
|
||||
.num_resources = 0,
|
||||
};
|
||||
|
||||
void omapfb_set_platform_data(struct omapfb_platform_data *data)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int ranges_overlap(unsigned long start1, unsigned long size1,
|
||||
unsigned long start2, unsigned long size2)
|
||||
{
|
||||
@ -327,7 +331,33 @@ static inline int omap_init_fb(void)
|
||||
|
||||
arch_initcall(omap_init_fb);
|
||||
|
||||
#else
|
||||
#elif defined(CONFIG_FB_OMAP2) || defined(CONFIG_FB_OMAP2_MODULE)
|
||||
|
||||
static u64 omap_fb_dma_mask = ~(u32)0;
|
||||
static struct omapfb_platform_data omapfb_config;
|
||||
|
||||
static struct platform_device omap_fb_device = {
|
||||
.name = "omapfb",
|
||||
.id = -1,
|
||||
.dev = {
|
||||
.dma_mask = &omap_fb_dma_mask,
|
||||
.coherent_dma_mask = ~(u32)0,
|
||||
.platform_data = &omapfb_config,
|
||||
},
|
||||
.num_resources = 0,
|
||||
};
|
||||
|
||||
void omapfb_set_platform_data(struct omapfb_platform_data *data)
|
||||
{
|
||||
omapfb_config = *data;
|
||||
}
|
||||
|
||||
static inline int omap_init_fb(void)
|
||||
{
|
||||
return platform_device_register(&omap_fb_device);
|
||||
}
|
||||
|
||||
arch_initcall(omap_init_fb);
|
||||
|
||||
void omapfb_reserve_sdram(void) {}
|
||||
unsigned long omapfb_reserve_sram(unsigned long sram_pstart,
|
||||
@ -339,5 +369,20 @@ unsigned long omapfb_reserve_sram(unsigned long sram_pstart,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void omapfb_set_platform_data(struct omapfb_platform_data *data)
|
||||
{
|
||||
}
|
||||
|
||||
void omapfb_reserve_sdram(void) {}
|
||||
unsigned long omapfb_reserve_sram(unsigned long sram_pstart,
|
||||
unsigned long sram_vstart,
|
||||
unsigned long sram_size,
|
||||
unsigned long start_avail,
|
||||
unsigned long size_avail)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
575
arch/arm/plat-omap/include/plat/display.h
Normal file
575
arch/arm/plat-omap/include/plat/display.h
Normal file
@ -0,0 +1,575 @@
|
||||
/*
|
||||
* linux/include/asm-arm/arch-omap/display.h
|
||||
*
|
||||
* Copyright (C) 2008 Nokia Corporation
|
||||
* Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __ASM_ARCH_OMAP_DISPLAY_H
|
||||
#define __ASM_ARCH_OMAP_DISPLAY_H
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/device.h>
|
||||
#include <asm/atomic.h>
|
||||
|
||||
#define DISPC_IRQ_FRAMEDONE (1 << 0)
|
||||
#define DISPC_IRQ_VSYNC (1 << 1)
|
||||
#define DISPC_IRQ_EVSYNC_EVEN (1 << 2)
|
||||
#define DISPC_IRQ_EVSYNC_ODD (1 << 3)
|
||||
#define DISPC_IRQ_ACBIAS_COUNT_STAT (1 << 4)
|
||||
#define DISPC_IRQ_PROG_LINE_NUM (1 << 5)
|
||||
#define DISPC_IRQ_GFX_FIFO_UNDERFLOW (1 << 6)
|
||||
#define DISPC_IRQ_GFX_END_WIN (1 << 7)
|
||||
#define DISPC_IRQ_PAL_GAMMA_MASK (1 << 8)
|
||||
#define DISPC_IRQ_OCP_ERR (1 << 9)
|
||||
#define DISPC_IRQ_VID1_FIFO_UNDERFLOW (1 << 10)
|
||||
#define DISPC_IRQ_VID1_END_WIN (1 << 11)
|
||||
#define DISPC_IRQ_VID2_FIFO_UNDERFLOW (1 << 12)
|
||||
#define DISPC_IRQ_VID2_END_WIN (1 << 13)
|
||||
#define DISPC_IRQ_SYNC_LOST (1 << 14)
|
||||
#define DISPC_IRQ_SYNC_LOST_DIGIT (1 << 15)
|
||||
#define DISPC_IRQ_WAKEUP (1 << 16)
|
||||
|
||||
struct omap_dss_device;
|
||||
struct omap_overlay_manager;
|
||||
|
||||
enum omap_display_type {
|
||||
OMAP_DISPLAY_TYPE_NONE = 0,
|
||||
OMAP_DISPLAY_TYPE_DPI = 1 << 0,
|
||||
OMAP_DISPLAY_TYPE_DBI = 1 << 1,
|
||||
OMAP_DISPLAY_TYPE_SDI = 1 << 2,
|
||||
OMAP_DISPLAY_TYPE_DSI = 1 << 3,
|
||||
OMAP_DISPLAY_TYPE_VENC = 1 << 4,
|
||||
};
|
||||
|
||||
enum omap_plane {
|
||||
OMAP_DSS_GFX = 0,
|
||||
OMAP_DSS_VIDEO1 = 1,
|
||||
OMAP_DSS_VIDEO2 = 2
|
||||
};
|
||||
|
||||
enum omap_channel {
|
||||
OMAP_DSS_CHANNEL_LCD = 0,
|
||||
OMAP_DSS_CHANNEL_DIGIT = 1,
|
||||
};
|
||||
|
||||
enum omap_color_mode {
|
||||
OMAP_DSS_COLOR_CLUT1 = 1 << 0, /* BITMAP 1 */
|
||||
OMAP_DSS_COLOR_CLUT2 = 1 << 1, /* BITMAP 2 */
|
||||
OMAP_DSS_COLOR_CLUT4 = 1 << 2, /* BITMAP 4 */
|
||||
OMAP_DSS_COLOR_CLUT8 = 1 << 3, /* BITMAP 8 */
|
||||
OMAP_DSS_COLOR_RGB12U = 1 << 4, /* RGB12, 16-bit container */
|
||||
OMAP_DSS_COLOR_ARGB16 = 1 << 5, /* ARGB16 */
|
||||
OMAP_DSS_COLOR_RGB16 = 1 << 6, /* RGB16 */
|
||||
OMAP_DSS_COLOR_RGB24U = 1 << 7, /* RGB24, 32-bit container */
|
||||
OMAP_DSS_COLOR_RGB24P = 1 << 8, /* RGB24, 24-bit container */
|
||||
OMAP_DSS_COLOR_YUV2 = 1 << 9, /* YUV2 4:2:2 co-sited */
|
||||
OMAP_DSS_COLOR_UYVY = 1 << 10, /* UYVY 4:2:2 co-sited */
|
||||
OMAP_DSS_COLOR_ARGB32 = 1 << 11, /* ARGB32 */
|
||||
OMAP_DSS_COLOR_RGBA32 = 1 << 12, /* RGBA32 */
|
||||
OMAP_DSS_COLOR_RGBX32 = 1 << 13, /* RGBx32 */
|
||||
|
||||
OMAP_DSS_COLOR_GFX_OMAP2 =
|
||||
OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 |
|
||||
OMAP_DSS_COLOR_CLUT4 | OMAP_DSS_COLOR_CLUT8 |
|
||||
OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_RGB16 |
|
||||
OMAP_DSS_COLOR_RGB24U | OMAP_DSS_COLOR_RGB24P,
|
||||
|
||||
OMAP_DSS_COLOR_VID_OMAP2 =
|
||||
OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
|
||||
OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_YUV2 |
|
||||
OMAP_DSS_COLOR_UYVY,
|
||||
|
||||
OMAP_DSS_COLOR_GFX_OMAP3 =
|
||||
OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 |
|
||||
OMAP_DSS_COLOR_CLUT4 | OMAP_DSS_COLOR_CLUT8 |
|
||||
OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_ARGB16 |
|
||||
OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
|
||||
OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_ARGB32 |
|
||||
OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32,
|
||||
|
||||
OMAP_DSS_COLOR_VID1_OMAP3 =
|
||||
OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_RGB16 |
|
||||
OMAP_DSS_COLOR_RGB24U | OMAP_DSS_COLOR_RGB24P |
|
||||
OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_UYVY,
|
||||
|
||||
OMAP_DSS_COLOR_VID2_OMAP3 =
|
||||
OMAP_DSS_COLOR_RGB12U | OMAP_DSS_COLOR_ARGB16 |
|
||||
OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U |
|
||||
OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_YUV2 |
|
||||
OMAP_DSS_COLOR_UYVY | OMAP_DSS_COLOR_ARGB32 |
|
||||
OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32,
|
||||
};
|
||||
|
||||
enum omap_lcd_display_type {
|
||||
OMAP_DSS_LCD_DISPLAY_STN,
|
||||
OMAP_DSS_LCD_DISPLAY_TFT,
|
||||
};
|
||||
|
||||
enum omap_dss_load_mode {
|
||||
OMAP_DSS_LOAD_CLUT_AND_FRAME = 0,
|
||||
OMAP_DSS_LOAD_CLUT_ONLY = 1,
|
||||
OMAP_DSS_LOAD_FRAME_ONLY = 2,
|
||||
OMAP_DSS_LOAD_CLUT_ONCE_FRAME = 3,
|
||||
};
|
||||
|
||||
enum omap_dss_trans_key_type {
|
||||
OMAP_DSS_COLOR_KEY_GFX_DST = 0,
|
||||
OMAP_DSS_COLOR_KEY_VID_SRC = 1,
|
||||
};
|
||||
|
||||
enum omap_rfbi_te_mode {
|
||||
OMAP_DSS_RFBI_TE_MODE_1 = 1,
|
||||
OMAP_DSS_RFBI_TE_MODE_2 = 2,
|
||||
};
|
||||
|
||||
enum omap_panel_config {
|
||||
OMAP_DSS_LCD_IVS = 1<<0,
|
||||
OMAP_DSS_LCD_IHS = 1<<1,
|
||||
OMAP_DSS_LCD_IPC = 1<<2,
|
||||
OMAP_DSS_LCD_IEO = 1<<3,
|
||||
OMAP_DSS_LCD_RF = 1<<4,
|
||||
OMAP_DSS_LCD_ONOFF = 1<<5,
|
||||
|
||||
OMAP_DSS_LCD_TFT = 1<<20,
|
||||
};
|
||||
|
||||
enum omap_dss_venc_type {
|
||||
OMAP_DSS_VENC_TYPE_COMPOSITE,
|
||||
OMAP_DSS_VENC_TYPE_SVIDEO,
|
||||
};
|
||||
|
||||
enum omap_display_caps {
|
||||
OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE = 1 << 0,
|
||||
OMAP_DSS_DISPLAY_CAP_TEAR_ELIM = 1 << 1,
|
||||
};
|
||||
|
||||
enum omap_dss_update_mode {
|
||||
OMAP_DSS_UPDATE_DISABLED = 0,
|
||||
OMAP_DSS_UPDATE_AUTO,
|
||||
OMAP_DSS_UPDATE_MANUAL,
|
||||
};
|
||||
|
||||
enum omap_dss_display_state {
|
||||
OMAP_DSS_DISPLAY_DISABLED = 0,
|
||||
OMAP_DSS_DISPLAY_ACTIVE,
|
||||
OMAP_DSS_DISPLAY_SUSPENDED,
|
||||
};
|
||||
|
||||
/* XXX perhaps this should be removed */
|
||||
enum omap_dss_overlay_managers {
|
||||
OMAP_DSS_OVL_MGR_LCD,
|
||||
OMAP_DSS_OVL_MGR_TV,
|
||||
};
|
||||
|
||||
enum omap_dss_rotation_type {
|
||||
OMAP_DSS_ROT_DMA = 0,
|
||||
OMAP_DSS_ROT_VRFB = 1,
|
||||
};
|
||||
|
||||
/* clockwise rotation angle */
|
||||
enum omap_dss_rotation_angle {
|
||||
OMAP_DSS_ROT_0 = 0,
|
||||
OMAP_DSS_ROT_90 = 1,
|
||||
OMAP_DSS_ROT_180 = 2,
|
||||
OMAP_DSS_ROT_270 = 3,
|
||||
};
|
||||
|
||||
enum omap_overlay_caps {
|
||||
OMAP_DSS_OVL_CAP_SCALE = 1 << 0,
|
||||
OMAP_DSS_OVL_CAP_DISPC = 1 << 1,
|
||||
};
|
||||
|
||||
enum omap_overlay_manager_caps {
|
||||
OMAP_DSS_OVL_MGR_CAP_DISPC = 1 << 0,
|
||||
};
|
||||
|
||||
/* RFBI */
|
||||
|
||||
struct rfbi_timings {
|
||||
int cs_on_time;
|
||||
int cs_off_time;
|
||||
int we_on_time;
|
||||
int we_off_time;
|
||||
int re_on_time;
|
||||
int re_off_time;
|
||||
int we_cycle_time;
|
||||
int re_cycle_time;
|
||||
int cs_pulse_width;
|
||||
int access_time;
|
||||
|
||||
int clk_div;
|
||||
|
||||
u32 tim[5]; /* set by rfbi_convert_timings() */
|
||||
|
||||
int converted;
|
||||
};
|
||||
|
||||
void omap_rfbi_write_command(const void *buf, u32 len);
|
||||
void omap_rfbi_read_data(void *buf, u32 len);
|
||||
void omap_rfbi_write_data(const void *buf, u32 len);
|
||||
void omap_rfbi_write_pixels(const void __iomem *buf, int scr_width,
|
||||
u16 x, u16 y,
|
||||
u16 w, u16 h);
|
||||
int omap_rfbi_enable_te(bool enable, unsigned line);
|
||||
int omap_rfbi_setup_te(enum omap_rfbi_te_mode mode,
|
||||
unsigned hs_pulse_time, unsigned vs_pulse_time,
|
||||
int hs_pol_inv, int vs_pol_inv, int extif_div);
|
||||
|
||||
/* DSI */
|
||||
void dsi_bus_lock(void);
|
||||
void dsi_bus_unlock(void);
|
||||
int dsi_vc_dcs_write(int channel, u8 *data, int len);
|
||||
int dsi_vc_dcs_write_nosync(int channel, u8 *data, int len);
|
||||
int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen);
|
||||
int dsi_vc_set_max_rx_packet_size(int channel, u16 len);
|
||||
int dsi_vc_send_null(int channel);
|
||||
int dsi_vc_send_bta_sync(int channel);
|
||||
|
||||
/* Board specific data */
|
||||
struct omap_dss_board_info {
|
||||
int (*get_last_off_on_transaction_id)(struct device *dev);
|
||||
int num_devices;
|
||||
struct omap_dss_device **devices;
|
||||
struct omap_dss_device *default_device;
|
||||
};
|
||||
|
||||
struct omap_video_timings {
|
||||
/* Unit: pixels */
|
||||
u16 x_res;
|
||||
/* Unit: pixels */
|
||||
u16 y_res;
|
||||
/* Unit: KHz */
|
||||
u32 pixel_clock;
|
||||
/* Unit: pixel clocks */
|
||||
u16 hsw; /* Horizontal synchronization pulse width */
|
||||
/* Unit: pixel clocks */
|
||||
u16 hfp; /* Horizontal front porch */
|
||||
/* Unit: pixel clocks */
|
||||
u16 hbp; /* Horizontal back porch */
|
||||
/* Unit: line clocks */
|
||||
u16 vsw; /* Vertical synchronization pulse width */
|
||||
/* Unit: line clocks */
|
||||
u16 vfp; /* Vertical front porch */
|
||||
/* Unit: line clocks */
|
||||
u16 vbp; /* Vertical back porch */
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OMAP2_DSS_VENC
|
||||
/* Hardcoded timings for tv modes. Venc only uses these to
|
||||
* identify the mode, and does not actually use the configs
|
||||
* itself. However, the configs should be something that
|
||||
* a normal monitor can also show */
|
||||
const extern struct omap_video_timings omap_dss_pal_timings;
|
||||
const extern struct omap_video_timings omap_dss_ntsc_timings;
|
||||
#endif
|
||||
|
||||
struct omap_overlay_info {
|
||||
bool enabled;
|
||||
|
||||
u32 paddr;
|
||||
void __iomem *vaddr;
|
||||
u16 screen_width;
|
||||
u16 width;
|
||||
u16 height;
|
||||
enum omap_color_mode color_mode;
|
||||
u8 rotation;
|
||||
enum omap_dss_rotation_type rotation_type;
|
||||
bool mirror;
|
||||
|
||||
u16 pos_x;
|
||||
u16 pos_y;
|
||||
u16 out_width; /* if 0, out_width == width */
|
||||
u16 out_height; /* if 0, out_height == height */
|
||||
u8 global_alpha;
|
||||
};
|
||||
|
||||
struct omap_overlay {
|
||||
struct kobject kobj;
|
||||
struct list_head list;
|
||||
|
||||
/* static fields */
|
||||
const char *name;
|
||||
int id;
|
||||
enum omap_color_mode supported_modes;
|
||||
enum omap_overlay_caps caps;
|
||||
|
||||
/* dynamic fields */
|
||||
struct omap_overlay_manager *manager;
|
||||
struct omap_overlay_info info;
|
||||
|
||||
/* if true, info has been changed, but not applied() yet */
|
||||
bool info_dirty;
|
||||
|
||||
int (*set_manager)(struct omap_overlay *ovl,
|
||||
struct omap_overlay_manager *mgr);
|
||||
int (*unset_manager)(struct omap_overlay *ovl);
|
||||
|
||||
int (*set_overlay_info)(struct omap_overlay *ovl,
|
||||
struct omap_overlay_info *info);
|
||||
void (*get_overlay_info)(struct omap_overlay *ovl,
|
||||
struct omap_overlay_info *info);
|
||||
|
||||
int (*wait_for_go)(struct omap_overlay *ovl);
|
||||
};
|
||||
|
||||
struct omap_overlay_manager_info {
|
||||
u32 default_color;
|
||||
|
||||
enum omap_dss_trans_key_type trans_key_type;
|
||||
u32 trans_key;
|
||||
bool trans_enabled;
|
||||
|
||||
bool alpha_enabled;
|
||||
};
|
||||
|
||||
struct omap_overlay_manager {
|
||||
struct kobject kobj;
|
||||
struct list_head list;
|
||||
|
||||
/* static fields */
|
||||
const char *name;
|
||||
int id;
|
||||
enum omap_overlay_manager_caps caps;
|
||||
int num_overlays;
|
||||
struct omap_overlay **overlays;
|
||||
enum omap_display_type supported_displays;
|
||||
|
||||
/* dynamic fields */
|
||||
struct omap_dss_device *device;
|
||||
struct omap_overlay_manager_info info;
|
||||
|
||||
bool device_changed;
|
||||
/* if true, info has been changed but not applied() yet */
|
||||
bool info_dirty;
|
||||
|
||||
int (*set_device)(struct omap_overlay_manager *mgr,
|
||||
struct omap_dss_device *dssdev);
|
||||
int (*unset_device)(struct omap_overlay_manager *mgr);
|
||||
|
||||
int (*set_manager_info)(struct omap_overlay_manager *mgr,
|
||||
struct omap_overlay_manager_info *info);
|
||||
void (*get_manager_info)(struct omap_overlay_manager *mgr,
|
||||
struct omap_overlay_manager_info *info);
|
||||
|
||||
int (*apply)(struct omap_overlay_manager *mgr);
|
||||
int (*wait_for_go)(struct omap_overlay_manager *mgr);
|
||||
};
|
||||
|
||||
struct omap_dss_device {
|
||||
struct device dev;
|
||||
|
||||
enum omap_display_type type;
|
||||
|
||||
union {
|
||||
struct {
|
||||
u8 data_lines;
|
||||
} dpi;
|
||||
|
||||
struct {
|
||||
u8 channel;
|
||||
u8 data_lines;
|
||||
} rfbi;
|
||||
|
||||
struct {
|
||||
u8 datapairs;
|
||||
} sdi;
|
||||
|
||||
struct {
|
||||
u8 clk_lane;
|
||||
u8 clk_pol;
|
||||
u8 data1_lane;
|
||||
u8 data1_pol;
|
||||
u8 data2_lane;
|
||||
u8 data2_pol;
|
||||
|
||||
struct {
|
||||
u16 regn;
|
||||
u16 regm;
|
||||
u16 regm3;
|
||||
u16 regm4;
|
||||
|
||||
u16 lp_clk_div;
|
||||
|
||||
u16 lck_div;
|
||||
u16 pck_div;
|
||||
} div;
|
||||
|
||||
bool ext_te;
|
||||
u8 ext_te_gpio;
|
||||
} dsi;
|
||||
|
||||
struct {
|
||||
enum omap_dss_venc_type type;
|
||||
bool invert_polarity;
|
||||
} venc;
|
||||
} phy;
|
||||
|
||||
struct {
|
||||
struct omap_video_timings timings;
|
||||
|
||||
int acbi; /* ac-bias pin transitions per interrupt */
|
||||
/* Unit: line clocks */
|
||||
int acb; /* ac-bias pin frequency */
|
||||
|
||||
enum omap_panel_config config;
|
||||
|
||||
u8 recommended_bpp;
|
||||
|
||||
struct omap_dss_device *ctrl;
|
||||
} panel;
|
||||
|
||||
struct {
|
||||
u8 pixel_size;
|
||||
struct rfbi_timings rfbi_timings;
|
||||
struct omap_dss_device *panel;
|
||||
} ctrl;
|
||||
|
||||
int reset_gpio;
|
||||
|
||||
int max_backlight_level;
|
||||
|
||||
const char *name;
|
||||
|
||||
/* used to match device to driver */
|
||||
const char *driver_name;
|
||||
|
||||
void *data;
|
||||
|
||||
struct omap_dss_driver *driver;
|
||||
|
||||
/* helper variable for driver suspend/resume */
|
||||
bool activate_after_resume;
|
||||
|
||||
enum omap_display_caps caps;
|
||||
|
||||
struct omap_overlay_manager *manager;
|
||||
|
||||
enum omap_dss_display_state state;
|
||||
|
||||
int (*enable)(struct omap_dss_device *dssdev);
|
||||
void (*disable)(struct omap_dss_device *dssdev);
|
||||
|
||||
int (*suspend)(struct omap_dss_device *dssdev);
|
||||
int (*resume)(struct omap_dss_device *dssdev);
|
||||
|
||||
void (*get_resolution)(struct omap_dss_device *dssdev,
|
||||
u16 *xres, u16 *yres);
|
||||
int (*get_recommended_bpp)(struct omap_dss_device *dssdev);
|
||||
|
||||
int (*check_timings)(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings);
|
||||
void (*set_timings)(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings);
|
||||
void (*get_timings)(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings);
|
||||
int (*update)(struct omap_dss_device *dssdev,
|
||||
u16 x, u16 y, u16 w, u16 h);
|
||||
int (*sync)(struct omap_dss_device *dssdev);
|
||||
int (*wait_vsync)(struct omap_dss_device *dssdev);
|
||||
|
||||
int (*set_update_mode)(struct omap_dss_device *dssdev,
|
||||
enum omap_dss_update_mode);
|
||||
enum omap_dss_update_mode (*get_update_mode)
|
||||
(struct omap_dss_device *dssdev);
|
||||
|
||||
int (*enable_te)(struct omap_dss_device *dssdev, bool enable);
|
||||
int (*get_te)(struct omap_dss_device *dssdev);
|
||||
|
||||
u8 (*get_rotate)(struct omap_dss_device *dssdev);
|
||||
int (*set_rotate)(struct omap_dss_device *dssdev, u8 rotate);
|
||||
|
||||
bool (*get_mirror)(struct omap_dss_device *dssdev);
|
||||
int (*set_mirror)(struct omap_dss_device *dssdev, bool enable);
|
||||
|
||||
int (*run_test)(struct omap_dss_device *dssdev, int test);
|
||||
int (*memory_read)(struct omap_dss_device *dssdev,
|
||||
void *buf, size_t size,
|
||||
u16 x, u16 y, u16 w, u16 h);
|
||||
|
||||
int (*set_wss)(struct omap_dss_device *dssdev, u32 wss);
|
||||
u32 (*get_wss)(struct omap_dss_device *dssdev);
|
||||
|
||||
/* platform specific */
|
||||
int (*platform_enable)(struct omap_dss_device *dssdev);
|
||||
void (*platform_disable)(struct omap_dss_device *dssdev);
|
||||
int (*set_backlight)(struct omap_dss_device *dssdev, int level);
|
||||
int (*get_backlight)(struct omap_dss_device *dssdev);
|
||||
};
|
||||
|
||||
struct omap_dss_driver {
|
||||
struct device_driver driver;
|
||||
|
||||
int (*probe)(struct omap_dss_device *);
|
||||
void (*remove)(struct omap_dss_device *);
|
||||
|
||||
int (*enable)(struct omap_dss_device *display);
|
||||
void (*disable)(struct omap_dss_device *display);
|
||||
int (*suspend)(struct omap_dss_device *display);
|
||||
int (*resume)(struct omap_dss_device *display);
|
||||
int (*run_test)(struct omap_dss_device *display, int test);
|
||||
|
||||
void (*setup_update)(struct omap_dss_device *dssdev,
|
||||
u16 x, u16 y, u16 w, u16 h);
|
||||
|
||||
int (*enable_te)(struct omap_dss_device *dssdev, bool enable);
|
||||
int (*wait_for_te)(struct omap_dss_device *dssdev);
|
||||
|
||||
u8 (*get_rotate)(struct omap_dss_device *dssdev);
|
||||
int (*set_rotate)(struct omap_dss_device *dssdev, u8 rotate);
|
||||
|
||||
bool (*get_mirror)(struct omap_dss_device *dssdev);
|
||||
int (*set_mirror)(struct omap_dss_device *dssdev, bool enable);
|
||||
|
||||
int (*memory_read)(struct omap_dss_device *dssdev,
|
||||
void *buf, size_t size,
|
||||
u16 x, u16 y, u16 w, u16 h);
|
||||
};
|
||||
|
||||
int omap_dss_register_driver(struct omap_dss_driver *);
|
||||
void omap_dss_unregister_driver(struct omap_dss_driver *);
|
||||
|
||||
int omap_dss_register_device(struct omap_dss_device *);
|
||||
void omap_dss_unregister_device(struct omap_dss_device *);
|
||||
|
||||
void omap_dss_get_device(struct omap_dss_device *dssdev);
|
||||
void omap_dss_put_device(struct omap_dss_device *dssdev);
|
||||
#define for_each_dss_dev(d) while ((d = omap_dss_get_next_device(d)) != NULL)
|
||||
struct omap_dss_device *omap_dss_get_next_device(struct omap_dss_device *from);
|
||||
struct omap_dss_device *omap_dss_find_device(void *data,
|
||||
int (*match)(struct omap_dss_device *dssdev, void *data));
|
||||
|
||||
int omap_dss_start_device(struct omap_dss_device *dssdev);
|
||||
void omap_dss_stop_device(struct omap_dss_device *dssdev);
|
||||
|
||||
int omap_dss_get_num_overlay_managers(void);
|
||||
struct omap_overlay_manager *omap_dss_get_overlay_manager(int num);
|
||||
|
||||
int omap_dss_get_num_overlays(void);
|
||||
struct omap_overlay *omap_dss_get_overlay(int num);
|
||||
|
||||
typedef void (*omap_dispc_isr_t) (void *arg, u32 mask);
|
||||
int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask);
|
||||
int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask);
|
||||
|
||||
int omap_dispc_wait_for_irq_timeout(u32 irqmask, unsigned long timeout);
|
||||
int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
|
||||
unsigned long timeout);
|
||||
|
||||
#define to_dss_driver(x) container_of((x), struct omap_dss_driver, driver)
|
||||
#define to_dss_device(x) container_of((x), struct omap_dss_device, dev)
|
||||
|
||||
#endif
|
@ -94,7 +94,10 @@
|
||||
|
||||
/* SMS register offsets - read/write with sms_{read,write}_reg() */
|
||||
|
||||
#define SMS_SYSCONFIG 0x010
|
||||
#define SMS_SYSCONFIG 0x010
|
||||
#define SMS_ROT_CONTROL(context) (0x180 + 0x10 * context)
|
||||
#define SMS_ROT_SIZE(context) (0x184 + 0x10 * context)
|
||||
#define SMS_ROT_PHYSICAL_BA(context) (0x188 + 0x10 * context)
|
||||
/* REVISIT: fill in other SMS registers here */
|
||||
|
||||
|
||||
@ -129,6 +132,10 @@ int omap2_sdrc_get_params(unsigned long r,
|
||||
void omap2_sms_save_context(void);
|
||||
void omap2_sms_restore_context(void);
|
||||
|
||||
void omap2_sms_write_rot_control(u32 val, unsigned ctx);
|
||||
void omap2_sms_write_rot_size(u32 val, unsigned ctx);
|
||||
void omap2_sms_write_rot_physical_ba(u32 val, unsigned ctx);
|
||||
|
||||
#ifdef CONFIG_ARCH_OMAP2
|
||||
|
||||
struct memory_timings {
|
||||
|
62
arch/arm/plat-omap/include/plat/vram.h
Normal file
62
arch/arm/plat-omap/include/plat/vram.h
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* VRAM manager for OMAP
|
||||
*
|
||||
* Copyright (C) 2009 Nokia Corporation
|
||||
* Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __OMAP_VRAM_H__
|
||||
#define __OMAP_VRAM_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#define OMAP_VRAM_MEMTYPE_SDRAM 0
|
||||
#define OMAP_VRAM_MEMTYPE_SRAM 1
|
||||
#define OMAP_VRAM_MEMTYPE_MAX 1
|
||||
|
||||
extern int omap_vram_add_region(unsigned long paddr, size_t size);
|
||||
extern int omap_vram_free(unsigned long paddr, size_t size);
|
||||
extern int omap_vram_alloc(int mtype, size_t size, unsigned long *paddr);
|
||||
extern int omap_vram_reserve(unsigned long paddr, size_t size);
|
||||
extern void omap_vram_get_info(unsigned long *vram, unsigned long *free_vram,
|
||||
unsigned long *largest_free_block);
|
||||
|
||||
#ifdef CONFIG_OMAP2_VRAM
|
||||
extern void omap_vram_set_sdram_vram(u32 size, u32 start);
|
||||
extern void omap_vram_set_sram_vram(u32 size, u32 start);
|
||||
|
||||
extern void omap_vram_reserve_sdram(void);
|
||||
extern unsigned long omap_vram_reserve_sram(unsigned long sram_pstart,
|
||||
unsigned long sram_vstart,
|
||||
unsigned long sram_size,
|
||||
unsigned long pstart_avail,
|
||||
unsigned long size_avail);
|
||||
#else
|
||||
static inline void omap_vram_set_sdram_vram(u32 size, u32 start) { }
|
||||
static inline void omap_vram_set_sram_vram(u32 size, u32 start) { }
|
||||
|
||||
static inline void omap_vram_reserve_sdram(void) { }
|
||||
static inline unsigned long omap_vram_reserve_sram(unsigned long sram_pstart,
|
||||
unsigned long sram_vstart,
|
||||
unsigned long sram_size,
|
||||
unsigned long pstart_avail,
|
||||
unsigned long size_avail)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
50
arch/arm/plat-omap/include/plat/vrfb.h
Normal file
50
arch/arm/plat-omap/include/plat/vrfb.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* VRFB Rotation Engine
|
||||
*
|
||||
* Copyright (C) 2009 Nokia Corporation
|
||||
* Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __OMAP_VRFB_H__
|
||||
#define __OMAP_VRFB_H__
|
||||
|
||||
#define OMAP_VRFB_LINE_LEN 2048
|
||||
|
||||
struct vrfb {
|
||||
u8 context;
|
||||
void __iomem *vaddr[4];
|
||||
unsigned long paddr[4];
|
||||
u16 xres;
|
||||
u16 yres;
|
||||
u16 xoffset;
|
||||
u16 yoffset;
|
||||
u8 bytespp;
|
||||
bool yuv_mode;
|
||||
};
|
||||
|
||||
extern int omap_vrfb_request_ctx(struct vrfb *vrfb);
|
||||
extern void omap_vrfb_release_ctx(struct vrfb *vrfb);
|
||||
extern void omap_vrfb_adjust_size(u16 *width, u16 *height,
|
||||
u8 bytespp);
|
||||
extern u32 omap_vrfb_min_phys_size(u16 width, u16 height, u8 bytespp);
|
||||
extern u16 omap_vrfb_max_height(u32 phys_size, u16 width, u8 bytespp);
|
||||
extern void omap_vrfb_setup(struct vrfb *vrfb, unsigned long paddr,
|
||||
u16 width, u16 height,
|
||||
unsigned bytespp, bool yuv_mode);
|
||||
extern int omap_vrfb_map_angle(struct vrfb *vrfb, u16 height, u8 rot);
|
||||
extern void omap_vrfb_restore_context(void);
|
||||
|
||||
#endif /* __VRFB_H */
|
@ -28,6 +28,7 @@
|
||||
#include <plat/sram.h>
|
||||
#include <plat/board.h>
|
||||
#include <plat/cpu.h>
|
||||
#include <plat/vram.h>
|
||||
|
||||
#include <plat/control.h>
|
||||
|
||||
@ -185,6 +186,13 @@ void __init omap_detect_sram(void)
|
||||
omap_sram_start + SRAM_BOOTLOADER_SZ,
|
||||
omap_sram_size - SRAM_BOOTLOADER_SZ);
|
||||
omap_sram_size -= reserved;
|
||||
|
||||
reserved = omap_vram_reserve_sram(omap_sram_start, omap_sram_base,
|
||||
omap_sram_size,
|
||||
omap_sram_start + SRAM_BOOTLOADER_SZ,
|
||||
omap_sram_size - SRAM_BOOTLOADER_SZ);
|
||||
omap_sram_size -= reserved;
|
||||
|
||||
omap_sram_ceil = omap_sram_base + omap_sram_size;
|
||||
}
|
||||
|
||||
|
@ -2165,6 +2165,7 @@ config FB_BROADSHEET
|
||||
a bridge adapter.
|
||||
|
||||
source "drivers/video/omap/Kconfig"
|
||||
source "drivers/video/omap2/Kconfig"
|
||||
|
||||
source "drivers/video/backlight/Kconfig"
|
||||
source "drivers/video/display/Kconfig"
|
||||
|
@ -124,6 +124,7 @@ obj-$(CONFIG_FB_SM501) += sm501fb.o
|
||||
obj-$(CONFIG_FB_XILINX) += xilinxfb.o
|
||||
obj-$(CONFIG_FB_SH_MOBILE_LCDC) += sh_mobile_lcdcfb.o
|
||||
obj-$(CONFIG_FB_OMAP) += omap/
|
||||
obj-y += omap2/
|
||||
obj-$(CONFIG_XEN_FBDEV_FRONTEND) += xen-fbfront.o
|
||||
obj-$(CONFIG_FB_CARMINE) += carminefb.o
|
||||
obj-$(CONFIG_FB_MB862XX) += mb862xx/
|
||||
|
@ -1,6 +1,7 @@
|
||||
config FB_OMAP
|
||||
tristate "OMAP frame buffer support (EXPERIMENTAL)"
|
||||
depends on FB && ARCH_OMAP
|
||||
depends on FB && ARCH_OMAP && (OMAP2_DSS = "n")
|
||||
|
||||
select FB_CFB_FILLRECT
|
||||
select FB_CFB_COPYAREA
|
||||
select FB_CFB_IMAGEBLIT
|
||||
@ -72,7 +73,7 @@ config FB_OMAP_LCD_MIPID
|
||||
|
||||
config FB_OMAP_BOOTLOADER_INIT
|
||||
bool "Check bootloader initialization"
|
||||
depends on FB_OMAP
|
||||
depends on FB_OMAP || FB_OMAP2
|
||||
help
|
||||
Say Y here if you want to enable checking if the bootloader has
|
||||
already initialized the display controller. In this case the
|
||||
|
@ -27,9 +27,9 @@
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include <plat/dma.h>
|
||||
#include <plat/omapfb.h>
|
||||
#include <plat/blizzard.h>
|
||||
|
||||
#include "omapfb.h"
|
||||
#include "dispc.h"
|
||||
|
||||
#define MODULE_NAME "blizzard"
|
||||
|
@ -24,11 +24,12 @@
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <plat/sram.h>
|
||||
#include <plat/omapfb.h>
|
||||
#include <plat/board.h>
|
||||
|
||||
#include "omapfb.h"
|
||||
#include "dispc.h"
|
||||
|
||||
#define MODULE_NAME "dispc"
|
||||
@ -188,6 +189,11 @@ static struct {
|
||||
struct omapfb_color_key color_key;
|
||||
} dispc;
|
||||
|
||||
static struct platform_device omapdss_device = {
|
||||
.name = "omapdss",
|
||||
.id = -1,
|
||||
};
|
||||
|
||||
static void enable_lcd_clocks(int enable);
|
||||
|
||||
static void inline dispc_write_reg(int idx, u32 val)
|
||||
@ -914,20 +920,20 @@ static irqreturn_t omap_dispc_irq_handler(int irq, void *dev)
|
||||
|
||||
static int get_dss_clocks(void)
|
||||
{
|
||||
dispc.dss_ick = clk_get(dispc.fbdev->dev, "ick");
|
||||
dispc.dss_ick = clk_get(&omapdss_device.dev, "ick");
|
||||
if (IS_ERR(dispc.dss_ick)) {
|
||||
dev_err(dispc.fbdev->dev, "can't get ick\n");
|
||||
return PTR_ERR(dispc.dss_ick);
|
||||
}
|
||||
|
||||
dispc.dss1_fck = clk_get(dispc.fbdev->dev, "dss1_fck");
|
||||
dispc.dss1_fck = clk_get(&omapdss_device.dev, "dss1_fck");
|
||||
if (IS_ERR(dispc.dss1_fck)) {
|
||||
dev_err(dispc.fbdev->dev, "can't get dss1_fck\n");
|
||||
clk_put(dispc.dss_ick);
|
||||
return PTR_ERR(dispc.dss1_fck);
|
||||
}
|
||||
|
||||
dispc.dss_54m_fck = clk_get(dispc.fbdev->dev, "tv_fck");
|
||||
dispc.dss_54m_fck = clk_get(&omapdss_device.dev, "tv_fck");
|
||||
if (IS_ERR(dispc.dss_54m_fck)) {
|
||||
dev_err(dispc.fbdev->dev, "can't get tv_fck\n");
|
||||
clk_put(dispc.dss_ick);
|
||||
@ -1379,6 +1385,12 @@ static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode,
|
||||
int skip_init = 0;
|
||||
int i;
|
||||
|
||||
r = platform_device_register(&omapdss_device);
|
||||
if (r) {
|
||||
dev_err(fbdev->dev, "can't register omapdss device\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
memset(&dispc, 0, sizeof(dispc));
|
||||
|
||||
dispc.base = ioremap(DISPC_BASE, SZ_1K);
|
||||
@ -1522,6 +1534,7 @@ static void omap_dispc_cleanup(void)
|
||||
free_irq(INT_24XX_DSS_IRQ, dispc.fbdev);
|
||||
put_dss_clocks();
|
||||
iounmap(dispc.base);
|
||||
platform_device_unregister(&omapdss_device);
|
||||
}
|
||||
|
||||
const struct lcd_ctrl omap2_int_ctrl = {
|
||||
|
@ -25,10 +25,11 @@
|
||||
#include <linux/fb.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include <plat/dma.h>
|
||||
#include <plat/omapfb.h>
|
||||
#include <plat/hwa742.h>
|
||||
#include "omapfb.h"
|
||||
|
||||
#define HWA742_REV_CODE_REG 0x0
|
||||
#define HWA742_CONFIG_REG 0x2
|
||||
|
@ -28,9 +28,10 @@
|
||||
#include <linux/i2c/twl4030.h>
|
||||
|
||||
#include <plat/mux.h>
|
||||
#include <plat/omapfb.h>
|
||||
#include <asm/mach-types.h>
|
||||
|
||||
#include "omapfb.h"
|
||||
|
||||
#define SDP2430_LCD_PANEL_BACKLIGHT_GPIO 91
|
||||
#define SDP2430_LCD_PANEL_ENABLE_GPIO 154
|
||||
#define SDP3430_LCD_PANEL_BACKLIGHT_GPIO 24
|
||||
|
@ -27,7 +27,8 @@
|
||||
|
||||
#include <plat/board-ams-delta.h>
|
||||
#include <mach/hardware.h>
|
||||
#include <plat/omapfb.h>
|
||||
|
||||
#include "omapfb.h"
|
||||
|
||||
#define AMS_DELTA_DEFAULT_CONTRAST 112
|
||||
|
||||
|
@ -26,7 +26,8 @@
|
||||
|
||||
#include <mach/gpio.h>
|
||||
#include <plat/mux.h>
|
||||
#include <plat/omapfb.h>
|
||||
|
||||
#include "omapfb.h"
|
||||
|
||||
/* #define USE_35INCH_LCD 1 */
|
||||
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include <linux/i2c/tps65010.h>
|
||||
|
||||
#include <mach/gpio.h>
|
||||
#include <plat/omapfb.h>
|
||||
#include "omapfb.h"
|
||||
|
||||
#define MODULE_NAME "omapfb-lcd_h3"
|
||||
|
||||
|
@ -22,7 +22,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <plat/omapfb.h>
|
||||
#include "omapfb.h"
|
||||
|
||||
static int h4_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
|
||||
{
|
||||
|
@ -29,7 +29,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <plat/omapfb.h>
|
||||
#include "omapfb.h"
|
||||
|
||||
static int htcherald_panel_init(struct lcd_panel *panel,
|
||||
struct omapfb_device *fbdev)
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <plat/fpga.h>
|
||||
#include <plat/omapfb.h>
|
||||
#include "omapfb.h"
|
||||
|
||||
static int innovator1510_panel_init(struct lcd_panel *panel,
|
||||
struct omapfb_device *fbdev)
|
||||
|
@ -23,7 +23,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <mach/gpio.h>
|
||||
#include <plat/omapfb.h>
|
||||
#include "omapfb.h"
|
||||
|
||||
#define MODULE_NAME "omapfb-lcd_h3"
|
||||
|
||||
|
@ -28,9 +28,10 @@
|
||||
|
||||
#include <mach/gpio.h>
|
||||
#include <plat/mux.h>
|
||||
#include <plat/omapfb.h>
|
||||
#include <asm/mach-types.h>
|
||||
|
||||
#include "omapfb.h"
|
||||
|
||||
#define LCD_PANEL_BACKLIGHT_GPIO (15 + OMAP_MAX_GPIO_LINES)
|
||||
#define LCD_PANEL_ENABLE_GPIO (7 + OMAP_MAX_GPIO_LINES)
|
||||
|
||||
|
@ -23,9 +23,10 @@
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#include <plat/omapfb.h>
|
||||
#include <plat/lcd_mipid.h>
|
||||
|
||||
#include "omapfb.h"
|
||||
|
||||
#define MIPID_MODULE_NAME "lcd_mipid"
|
||||
|
||||
#define MIPID_CMD_READ_DISP_ID 0x04
|
||||
|
@ -27,9 +27,10 @@
|
||||
#include <linux/i2c/twl4030.h>
|
||||
|
||||
#include <plat/mux.h>
|
||||
#include <plat/omapfb.h>
|
||||
#include <asm/mach-types.h>
|
||||
|
||||
#include "omapfb.h"
|
||||
|
||||
#define LCD_PANEL_ENABLE_GPIO 154
|
||||
#define LCD_PANEL_LR 128
|
||||
#define LCD_PANEL_UD 129
|
||||
|
@ -26,9 +26,11 @@
|
||||
#include <linux/i2c/twl4030.h>
|
||||
|
||||
#include <plat/mux.h>
|
||||
#include <plat/omapfb.h>
|
||||
#include <plat/mux.h>
|
||||
#include <asm/mach-types.h>
|
||||
|
||||
#include "omapfb.h"
|
||||
|
||||
#define LCD_PANEL_ENABLE_GPIO 170
|
||||
|
||||
static int omap3beagle_panel_init(struct lcd_panel *panel,
|
||||
|
@ -26,9 +26,10 @@
|
||||
#include <linux/i2c/twl4030.h>
|
||||
|
||||
#include <plat/mux.h>
|
||||
#include <plat/omapfb.h>
|
||||
#include <asm/mach-types.h>
|
||||
|
||||
#include "omapfb.h"
|
||||
|
||||
#define LCD_PANEL_ENABLE_GPIO 153
|
||||
#define LCD_PANEL_LR 2
|
||||
#define LCD_PANEL_UD 3
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
#include <mach/gpio.h>
|
||||
#include <plat/mux.h>
|
||||
#include <plat/omapfb.h>
|
||||
#include "omapfb.h"
|
||||
|
||||
static int osk_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
|
||||
{
|
||||
|
@ -25,9 +25,10 @@
|
||||
|
||||
#include <mach/gpio.h>
|
||||
#include <plat/mux.h>
|
||||
#include <plat/omapfb.h>
|
||||
#include <asm/mach-types.h>
|
||||
|
||||
#include "omapfb.h"
|
||||
|
||||
#define LCD_ENABLE 144
|
||||
|
||||
static int overo_panel_init(struct lcd_panel *panel,
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <plat/fpga.h>
|
||||
#include <plat/omapfb.h>
|
||||
#include "omapfb.h"
|
||||
|
||||
static int palmte_panel_init(struct lcd_panel *panel,
|
||||
struct omapfb_device *fbdev)
|
||||
|
@ -30,7 +30,7 @@ GPIO13 - screen blanking
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <mach/gpio.h>
|
||||
#include <plat/omapfb.h>
|
||||
#include "omapfb.h"
|
||||
|
||||
static int palmtt_panel_init(struct lcd_panel *panel,
|
||||
struct omapfb_device *fbdev)
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <plat/omapfb.h>
|
||||
#include "omapfb.h"
|
||||
|
||||
static int palmz71_panel_init(struct lcd_panel *panel,
|
||||
struct omapfb_device *fbdev)
|
||||
|
@ -30,10 +30,11 @@
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include <plat/dma.h>
|
||||
#include <plat/omapfb.h>
|
||||
|
||||
#include <asm/mach-types.h>
|
||||
|
||||
#include "omapfb.h"
|
||||
|
||||
#include "lcdc.h"
|
||||
|
||||
#define MODULE_NAME "lcdc"
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* File: arch/arm/plat-omap/include/mach/omapfb.h
|
||||
* File: drivers/video/omap/omapfb.h
|
||||
*
|
||||
* Framebuffer driver for TI OMAP boards
|
||||
*
|
||||
@ -24,152 +24,13 @@
|
||||
#ifndef __OMAPFB_H
|
||||
#define __OMAPFB_H
|
||||
|
||||
#include <asm/ioctl.h>
|
||||
#include <asm/types.h>
|
||||
|
||||
/* IOCTL commands. */
|
||||
|
||||
#define OMAP_IOW(num, dtype) _IOW('O', num, dtype)
|
||||
#define OMAP_IOR(num, dtype) _IOR('O', num, dtype)
|
||||
#define OMAP_IOWR(num, dtype) _IOWR('O', num, dtype)
|
||||
#define OMAP_IO(num) _IO('O', num)
|
||||
|
||||
#define OMAPFB_MIRROR OMAP_IOW(31, int)
|
||||
#define OMAPFB_SYNC_GFX OMAP_IO(37)
|
||||
#define OMAPFB_VSYNC OMAP_IO(38)
|
||||
#define OMAPFB_SET_UPDATE_MODE OMAP_IOW(40, int)
|
||||
#define OMAPFB_GET_CAPS OMAP_IOR(42, struct omapfb_caps)
|
||||
#define OMAPFB_GET_UPDATE_MODE OMAP_IOW(43, int)
|
||||
#define OMAPFB_LCD_TEST OMAP_IOW(45, int)
|
||||
#define OMAPFB_CTRL_TEST OMAP_IOW(46, int)
|
||||
#define OMAPFB_UPDATE_WINDOW_OLD OMAP_IOW(47, struct omapfb_update_window_old)
|
||||
#define OMAPFB_SET_COLOR_KEY OMAP_IOW(50, struct omapfb_color_key)
|
||||
#define OMAPFB_GET_COLOR_KEY OMAP_IOW(51, struct omapfb_color_key)
|
||||
#define OMAPFB_SETUP_PLANE OMAP_IOW(52, struct omapfb_plane_info)
|
||||
#define OMAPFB_QUERY_PLANE OMAP_IOW(53, struct omapfb_plane_info)
|
||||
#define OMAPFB_UPDATE_WINDOW OMAP_IOW(54, struct omapfb_update_window)
|
||||
#define OMAPFB_SETUP_MEM OMAP_IOW(55, struct omapfb_mem_info)
|
||||
#define OMAPFB_QUERY_MEM OMAP_IOW(56, struct omapfb_mem_info)
|
||||
|
||||
#define OMAPFB_CAPS_GENERIC_MASK 0x00000fff
|
||||
#define OMAPFB_CAPS_LCDC_MASK 0x00fff000
|
||||
#define OMAPFB_CAPS_PANEL_MASK 0xff000000
|
||||
|
||||
#define OMAPFB_CAPS_MANUAL_UPDATE 0x00001000
|
||||
#define OMAPFB_CAPS_TEARSYNC 0x00002000
|
||||
#define OMAPFB_CAPS_PLANE_RELOCATE_MEM 0x00004000
|
||||
#define OMAPFB_CAPS_PLANE_SCALE 0x00008000
|
||||
#define OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE 0x00010000
|
||||
#define OMAPFB_CAPS_WINDOW_SCALE 0x00020000
|
||||
#define OMAPFB_CAPS_WINDOW_OVERLAY 0x00040000
|
||||
#define OMAPFB_CAPS_WINDOW_ROTATE 0x00080000
|
||||
#define OMAPFB_CAPS_SET_BACKLIGHT 0x01000000
|
||||
|
||||
/* Values from DSP must map to lower 16-bits */
|
||||
#define OMAPFB_FORMAT_MASK 0x00ff
|
||||
#define OMAPFB_FORMAT_FLAG_DOUBLE 0x0100
|
||||
#define OMAPFB_FORMAT_FLAG_TEARSYNC 0x0200
|
||||
#define OMAPFB_FORMAT_FLAG_FORCE_VSYNC 0x0400
|
||||
#define OMAPFB_FORMAT_FLAG_ENABLE_OVERLAY 0x0800
|
||||
#define OMAPFB_FORMAT_FLAG_DISABLE_OVERLAY 0x1000
|
||||
#include <linux/fb.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/omapfb.h>
|
||||
|
||||
#define OMAPFB_EVENT_READY 1
|
||||
#define OMAPFB_EVENT_DISABLED 2
|
||||
|
||||
#define OMAPFB_MEMTYPE_SDRAM 0
|
||||
#define OMAPFB_MEMTYPE_SRAM 1
|
||||
#define OMAPFB_MEMTYPE_MAX 1
|
||||
|
||||
enum omapfb_color_format {
|
||||
OMAPFB_COLOR_RGB565 = 0,
|
||||
OMAPFB_COLOR_YUV422,
|
||||
OMAPFB_COLOR_YUV420,
|
||||
OMAPFB_COLOR_CLUT_8BPP,
|
||||
OMAPFB_COLOR_CLUT_4BPP,
|
||||
OMAPFB_COLOR_CLUT_2BPP,
|
||||
OMAPFB_COLOR_CLUT_1BPP,
|
||||
OMAPFB_COLOR_RGB444,
|
||||
OMAPFB_COLOR_YUY422,
|
||||
};
|
||||
|
||||
struct omapfb_update_window {
|
||||
__u32 x, y;
|
||||
__u32 width, height;
|
||||
__u32 format;
|
||||
__u32 out_x, out_y;
|
||||
__u32 out_width, out_height;
|
||||
__u32 reserved[8];
|
||||
};
|
||||
|
||||
struct omapfb_update_window_old {
|
||||
__u32 x, y;
|
||||
__u32 width, height;
|
||||
__u32 format;
|
||||
};
|
||||
|
||||
enum omapfb_plane {
|
||||
OMAPFB_PLANE_GFX = 0,
|
||||
OMAPFB_PLANE_VID1,
|
||||
OMAPFB_PLANE_VID2,
|
||||
};
|
||||
|
||||
enum omapfb_channel_out {
|
||||
OMAPFB_CHANNEL_OUT_LCD = 0,
|
||||
OMAPFB_CHANNEL_OUT_DIGIT,
|
||||
};
|
||||
|
||||
struct omapfb_plane_info {
|
||||
__u32 pos_x;
|
||||
__u32 pos_y;
|
||||
__u8 enabled;
|
||||
__u8 channel_out;
|
||||
__u8 mirror;
|
||||
__u8 reserved1;
|
||||
__u32 out_width;
|
||||
__u32 out_height;
|
||||
__u32 reserved2[12];
|
||||
};
|
||||
|
||||
struct omapfb_mem_info {
|
||||
__u32 size;
|
||||
__u8 type;
|
||||
__u8 reserved[3];
|
||||
};
|
||||
|
||||
struct omapfb_caps {
|
||||
__u32 ctrl;
|
||||
__u32 plane_color;
|
||||
__u32 wnd_color;
|
||||
};
|
||||
|
||||
enum omapfb_color_key_type {
|
||||
OMAPFB_COLOR_KEY_DISABLED = 0,
|
||||
OMAPFB_COLOR_KEY_GFX_DST,
|
||||
OMAPFB_COLOR_KEY_VID_SRC,
|
||||
};
|
||||
|
||||
struct omapfb_color_key {
|
||||
__u8 channel_out;
|
||||
__u32 background;
|
||||
__u32 trans_key;
|
||||
__u8 key_type;
|
||||
};
|
||||
|
||||
enum omapfb_update_mode {
|
||||
OMAPFB_UPDATE_DISABLED = 0,
|
||||
OMAPFB_AUTO_UPDATE,
|
||||
OMAPFB_MANUAL_UPDATE
|
||||
};
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#include <linux/completion.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include <plat/board.h>
|
||||
|
||||
#define OMAP_LCDC_INV_VSYNC 0x0001
|
||||
#define OMAP_LCDC_INV_HSYNC 0x0002
|
||||
#define OMAP_LCDC_INV_PIX_CLOCK 0x0004
|
||||
@ -184,12 +45,6 @@ enum omapfb_update_mode {
|
||||
#define OMAPFB_PLANE_XRES_MIN 8
|
||||
#define OMAPFB_PLANE_YRES_MIN 8
|
||||
|
||||
#ifdef CONFIG_ARCH_OMAP1
|
||||
#define OMAPFB_PLANE_NUM 1
|
||||
#else
|
||||
#define OMAPFB_PLANE_NUM 3
|
||||
#endif
|
||||
|
||||
struct omapfb_device;
|
||||
|
||||
struct lcd_panel {
|
||||
@ -256,7 +111,7 @@ struct lcd_ctrl_extif {
|
||||
void (*read_data) (void *buf, unsigned int len);
|
||||
void (*write_data) (const void *buf, unsigned int len);
|
||||
void (*transfer_area) (int width, int height,
|
||||
void (callback)(void * data), void *data);
|
||||
void (callback)(void *data), void *data);
|
||||
int (*setup_tearsync) (unsigned pin_cnt,
|
||||
unsigned hs_pulse_time, unsigned vs_pulse_time,
|
||||
int hs_pol_inv, int vs_pol_inv, int div);
|
||||
@ -275,20 +130,6 @@ typedef int (*omapfb_notifier_callback_t)(struct notifier_block *,
|
||||
unsigned long event,
|
||||
void *fbi);
|
||||
|
||||
struct omapfb_mem_region {
|
||||
u32 paddr;
|
||||
void __iomem *vaddr;
|
||||
unsigned long size;
|
||||
u8 type; /* OMAPFB_PLANE_MEM_* */
|
||||
unsigned alloc:1; /* allocated by the driver */
|
||||
unsigned map:1; /* kernel mapped by the driver */
|
||||
};
|
||||
|
||||
struct omapfb_mem_desc {
|
||||
int region_cnt;
|
||||
struct omapfb_mem_region region[OMAPFB_PLANE_NUM];
|
||||
};
|
||||
|
||||
struct lcd_ctrl {
|
||||
const char *name;
|
||||
void *data;
|
||||
@ -331,9 +172,9 @@ struct lcd_ctrl {
|
||||
};
|
||||
|
||||
enum omapfb_state {
|
||||
OMAPFB_DISABLED = 0,
|
||||
OMAPFB_SUSPENDED= 99,
|
||||
OMAPFB_ACTIVE = 100
|
||||
OMAPFB_DISABLED = 0,
|
||||
OMAPFB_SUSPENDED = 99,
|
||||
OMAPFB_ACTIVE = 100
|
||||
};
|
||||
|
||||
struct omapfb_plane_struct {
|
||||
@ -345,8 +186,8 @@ struct omapfb_plane_struct {
|
||||
|
||||
struct omapfb_device {
|
||||
int state;
|
||||
int ext_lcdc; /* Using external
|
||||
LCD controller */
|
||||
int ext_lcdc; /* Using external
|
||||
LCD controller */
|
||||
struct mutex rqueue_mutex;
|
||||
|
||||
int palette_size;
|
||||
@ -364,19 +205,12 @@ struct omapfb_device {
|
||||
struct fb_info *fb_info[OMAPFB_PLANE_NUM];
|
||||
};
|
||||
|
||||
struct omapfb_platform_data {
|
||||
struct omap_lcd_config lcd;
|
||||
struct omapfb_mem_desc mem_desc;
|
||||
void *ctrl_platform_data;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ARCH_OMAP1
|
||||
extern struct lcd_ctrl omap1_lcd_ctrl;
|
||||
#else
|
||||
extern struct lcd_ctrl omap2_disp_ctrl;
|
||||
#endif
|
||||
|
||||
extern void omapfb_reserve_sdram(void);
|
||||
extern void omapfb_register_panel(struct lcd_panel *panel);
|
||||
extern void omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval);
|
||||
extern void omapfb_notify_clients(struct omapfb_device *fbdev,
|
||||
@ -390,9 +224,4 @@ extern int omapfb_update_window_async(struct fb_info *fbi,
|
||||
void (*callback)(void *),
|
||||
void *callback_data);
|
||||
|
||||
/* in arch/arm/plat-omap/fb.c */
|
||||
extern void omapfb_set_ctrl_platform_data(void *pdata);
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* __OMAPFB_H */
|
@ -29,8 +29,8 @@
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <plat/dma.h>
|
||||
#include <plat/omapfb.h>
|
||||
|
||||
#include "omapfb.h"
|
||||
#include "lcdc.h"
|
||||
#include "dispc.h"
|
||||
|
||||
|
@ -27,8 +27,7 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <plat/omapfb.h>
|
||||
|
||||
#include "omapfb.h"
|
||||
#include "dispc.h"
|
||||
|
||||
/* To work around an RFBI transfer rate limitation */
|
||||
|
@ -23,10 +23,11 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include <plat/dma.h>
|
||||
#include <plat/omapfb.h>
|
||||
|
||||
#include "omapfb.h"
|
||||
#include "lcdc.h"
|
||||
|
||||
#define MODULE_NAME "omapfb-sossi"
|
||||
|
9
drivers/video/omap2/Kconfig
Normal file
9
drivers/video/omap2/Kconfig
Normal file
@ -0,0 +1,9 @@
|
||||
config OMAP2_VRAM
|
||||
bool
|
||||
|
||||
config OMAP2_VRFB
|
||||
bool
|
||||
|
||||
source "drivers/video/omap2/dss/Kconfig"
|
||||
source "drivers/video/omap2/omapfb/Kconfig"
|
||||
source "drivers/video/omap2/displays/Kconfig"
|
6
drivers/video/omap2/Makefile
Normal file
6
drivers/video/omap2/Makefile
Normal file
@ -0,0 +1,6 @@
|
||||
obj-$(CONFIG_OMAP2_VRAM) += vram.o
|
||||
obj-$(CONFIG_OMAP2_VRFB) += vrfb.o
|
||||
|
||||
obj-y += dss/
|
||||
obj-y += omapfb/
|
||||
obj-y += displays/
|
22
drivers/video/omap2/displays/Kconfig
Normal file
22
drivers/video/omap2/displays/Kconfig
Normal file
@ -0,0 +1,22 @@
|
||||
menu "OMAP2/3 Display Device Drivers"
|
||||
depends on OMAP2_DSS
|
||||
|
||||
config PANEL_GENERIC
|
||||
tristate "Generic Panel"
|
||||
help
|
||||
Generic panel driver.
|
||||
Used for DVI output for Beagle and OMAP3 SDP.
|
||||
|
||||
config PANEL_SHARP_LS037V7DW01
|
||||
tristate "Sharp LS037V7DW01 LCD Panel"
|
||||
depends on OMAP2_DSS
|
||||
help
|
||||
LCD Panel used in TI's SDP3430 and EVM boards
|
||||
|
||||
config PANEL_TAAL
|
||||
tristate "Taal DSI Panel"
|
||||
depends on OMAP2_DSS_DSI
|
||||
help
|
||||
Taal DSI command mode panel from TPO.
|
||||
|
||||
endmenu
|
4
drivers/video/omap2/displays/Makefile
Normal file
4
drivers/video/omap2/displays/Makefile
Normal file
@ -0,0 +1,4 @@
|
||||
obj-$(CONFIG_PANEL_GENERIC) += panel-generic.o
|
||||
obj-$(CONFIG_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o
|
||||
|
||||
obj-$(CONFIG_PANEL_TAAL) += panel-taal.o
|
104
drivers/video/omap2/displays/panel-generic.c
Normal file
104
drivers/video/omap2/displays/panel-generic.c
Normal file
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Generic panel support
|
||||
*
|
||||
* Copyright (C) 2008 Nokia Corporation
|
||||
* Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include <plat/display.h>
|
||||
|
||||
static struct omap_video_timings generic_panel_timings = {
|
||||
/* 640 x 480 @ 60 Hz Reduced blanking VESA CVT 0.31M3-R */
|
||||
.x_res = 640,
|
||||
.y_res = 480,
|
||||
.pixel_clock = 23500,
|
||||
.hfp = 48,
|
||||
.hsw = 32,
|
||||
.hbp = 80,
|
||||
.vfp = 3,
|
||||
.vsw = 4,
|
||||
.vbp = 7,
|
||||
};
|
||||
|
||||
static int generic_panel_probe(struct omap_dss_device *dssdev)
|
||||
{
|
||||
dssdev->panel.config = OMAP_DSS_LCD_TFT;
|
||||
dssdev->panel.timings = generic_panel_timings;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void generic_panel_remove(struct omap_dss_device *dssdev)
|
||||
{
|
||||
}
|
||||
|
||||
static int generic_panel_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
if (dssdev->platform_enable)
|
||||
r = dssdev->platform_enable(dssdev);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void generic_panel_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
if (dssdev->platform_disable)
|
||||
dssdev->platform_disable(dssdev);
|
||||
}
|
||||
|
||||
static int generic_panel_suspend(struct omap_dss_device *dssdev)
|
||||
{
|
||||
generic_panel_disable(dssdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int generic_panel_resume(struct omap_dss_device *dssdev)
|
||||
{
|
||||
return generic_panel_enable(dssdev);
|
||||
}
|
||||
|
||||
static struct omap_dss_driver generic_driver = {
|
||||
.probe = generic_panel_probe,
|
||||
.remove = generic_panel_remove,
|
||||
|
||||
.enable = generic_panel_enable,
|
||||
.disable = generic_panel_disable,
|
||||
.suspend = generic_panel_suspend,
|
||||
.resume = generic_panel_resume,
|
||||
|
||||
.driver = {
|
||||
.name = "generic_panel",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init generic_panel_drv_init(void)
|
||||
{
|
||||
return omap_dss_register_driver(&generic_driver);
|
||||
}
|
||||
|
||||
static void __exit generic_panel_drv_exit(void)
|
||||
{
|
||||
omap_dss_unregister_driver(&generic_driver);
|
||||
}
|
||||
|
||||
module_init(generic_panel_drv_init);
|
||||
module_exit(generic_panel_drv_exit);
|
||||
MODULE_LICENSE("GPL");
|
153
drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c
Normal file
153
drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c
Normal file
@ -0,0 +1,153 @@
|
||||
/*
|
||||
* LCD panel driver for Sharp LS037V7DW01
|
||||
*
|
||||
* Copyright (C) 2008 Nokia Corporation
|
||||
* Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include <plat/display.h>
|
||||
|
||||
struct sharp_data {
|
||||
/* XXX This regulator should actually be in SDP board file, not here,
|
||||
* as it doesn't actually power the LCD, but something else that
|
||||
* affects the output to LCD (I think. Somebody clarify). It doesn't do
|
||||
* harm here, as SDP is the only board using this currently */
|
||||
struct regulator *vdvi_reg;
|
||||
};
|
||||
|
||||
static struct omap_video_timings sharp_ls_timings = {
|
||||
.x_res = 480,
|
||||
.y_res = 640,
|
||||
|
||||
.pixel_clock = 19200,
|
||||
|
||||
.hsw = 2,
|
||||
.hfp = 1,
|
||||
.hbp = 28,
|
||||
|
||||
.vsw = 1,
|
||||
.vfp = 1,
|
||||
.vbp = 1,
|
||||
};
|
||||
|
||||
static int sharp_ls_panel_probe(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct sharp_data *sd;
|
||||
|
||||
dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
|
||||
OMAP_DSS_LCD_IHS;
|
||||
dssdev->panel.acb = 0x28;
|
||||
dssdev->panel.timings = sharp_ls_timings;
|
||||
|
||||
sd = kzalloc(sizeof(*sd), GFP_KERNEL);
|
||||
if (!sd)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_set_drvdata(&dssdev->dev, sd);
|
||||
|
||||
sd->vdvi_reg = regulator_get(&dssdev->dev, "vdvi");
|
||||
if (IS_ERR(sd->vdvi_reg)) {
|
||||
kfree(sd);
|
||||
pr_err("failed to get VDVI regulator\n");
|
||||
return PTR_ERR(sd->vdvi_reg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sharp_ls_panel_remove(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct sharp_data *sd = dev_get_drvdata(&dssdev->dev);
|
||||
|
||||
regulator_put(sd->vdvi_reg);
|
||||
|
||||
kfree(sd);
|
||||
}
|
||||
|
||||
static int sharp_ls_panel_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct sharp_data *sd = dev_get_drvdata(&dssdev->dev);
|
||||
int r = 0;
|
||||
|
||||
/* wait couple of vsyncs until enabling the LCD */
|
||||
msleep(50);
|
||||
|
||||
regulator_enable(sd->vdvi_reg);
|
||||
|
||||
if (dssdev->platform_enable)
|
||||
r = dssdev->platform_enable(dssdev);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void sharp_ls_panel_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct sharp_data *sd = dev_get_drvdata(&dssdev->dev);
|
||||
|
||||
if (dssdev->platform_disable)
|
||||
dssdev->platform_disable(dssdev);
|
||||
|
||||
regulator_disable(sd->vdvi_reg);
|
||||
|
||||
/* wait at least 5 vsyncs after disabling the LCD */
|
||||
|
||||
msleep(100);
|
||||
}
|
||||
|
||||
static int sharp_ls_panel_suspend(struct omap_dss_device *dssdev)
|
||||
{
|
||||
sharp_ls_panel_disable(dssdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sharp_ls_panel_resume(struct omap_dss_device *dssdev)
|
||||
{
|
||||
return sharp_ls_panel_enable(dssdev);
|
||||
}
|
||||
|
||||
static struct omap_dss_driver sharp_ls_driver = {
|
||||
.probe = sharp_ls_panel_probe,
|
||||
.remove = sharp_ls_panel_remove,
|
||||
|
||||
.enable = sharp_ls_panel_enable,
|
||||
.disable = sharp_ls_panel_disable,
|
||||
.suspend = sharp_ls_panel_suspend,
|
||||
.resume = sharp_ls_panel_resume,
|
||||
|
||||
.driver = {
|
||||
.name = "sharp_ls_panel",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init sharp_ls_panel_drv_init(void)
|
||||
{
|
||||
return omap_dss_register_driver(&sharp_ls_driver);
|
||||
}
|
||||
|
||||
static void __exit sharp_ls_panel_drv_exit(void)
|
||||
{
|
||||
omap_dss_unregister_driver(&sharp_ls_driver);
|
||||
}
|
||||
|
||||
module_init(sharp_ls_panel_drv_init);
|
||||
module_exit(sharp_ls_panel_drv_exit);
|
||||
MODULE_LICENSE("GPL");
|
1003
drivers/video/omap2/displays/panel-taal.c
Normal file
1003
drivers/video/omap2/displays/panel-taal.c
Normal file
File diff suppressed because it is too large
Load Diff
89
drivers/video/omap2/dss/Kconfig
Normal file
89
drivers/video/omap2/dss/Kconfig
Normal file
@ -0,0 +1,89 @@
|
||||
menuconfig OMAP2_DSS
|
||||
tristate "OMAP2/3 Display Subsystem support (EXPERIMENTAL)"
|
||||
depends on ARCH_OMAP2 || ARCH_OMAP3
|
||||
help
|
||||
OMAP2/3 Display Subsystem support.
|
||||
|
||||
if OMAP2_DSS
|
||||
|
||||
config OMAP2_VRAM_SIZE
|
||||
int "VRAM size (MB)"
|
||||
range 0 32
|
||||
default 0
|
||||
help
|
||||
The amount of SDRAM to reserve at boot time for video RAM use.
|
||||
This VRAM will be used by omapfb and other drivers that need
|
||||
large continuous RAM area for video use.
|
||||
|
||||
You can also set this with "vram=<bytes>" kernel argument, or
|
||||
in the board file.
|
||||
|
||||
config OMAP2_DSS_DEBUG_SUPPORT
|
||||
bool "Debug support"
|
||||
default y
|
||||
help
|
||||
This enables debug messages. You need to enable printing
|
||||
with 'debug' module parameter.
|
||||
|
||||
config OMAP2_DSS_RFBI
|
||||
bool "RFBI support"
|
||||
default n
|
||||
help
|
||||
MIPI DBI, or RFBI (Remote Framebuffer Interface), support.
|
||||
|
||||
config OMAP2_DSS_VENC
|
||||
bool "VENC support"
|
||||
default y
|
||||
help
|
||||
OMAP Video Encoder support.
|
||||
|
||||
config OMAP2_DSS_SDI
|
||||
bool "SDI support"
|
||||
depends on ARCH_OMAP3
|
||||
default n
|
||||
help
|
||||
SDI (Serial Display Interface) support.
|
||||
|
||||
config OMAP2_DSS_DSI
|
||||
bool "DSI support"
|
||||
depends on ARCH_OMAP3
|
||||
default n
|
||||
help
|
||||
MIPI DSI support.
|
||||
|
||||
config OMAP2_DSS_USE_DSI_PLL
|
||||
bool "Use DSI PLL for PCLK (EXPERIMENTAL)"
|
||||
default n
|
||||
depends on OMAP2_DSS_DSI
|
||||
help
|
||||
Use DSI PLL to generate pixel clock. Currently only for DPI output.
|
||||
DSI PLL can be used to generate higher and more precise pixel clocks.
|
||||
|
||||
config OMAP2_DSS_FAKE_VSYNC
|
||||
bool "Fake VSYNC irq from manual update displays"
|
||||
default n
|
||||
help
|
||||
If this is selected, DSI will generate a fake DISPC VSYNC interrupt
|
||||
when DSI has sent a frame. This is only needed with DSI or RFBI
|
||||
displays using manual mode, and you want VSYNC to, for example,
|
||||
time animation.
|
||||
|
||||
config OMAP2_DSS_MIN_FCK_PER_PCK
|
||||
int "Minimum FCK/PCK ratio (for scaling)"
|
||||
range 0 32
|
||||
default 0
|
||||
help
|
||||
This can be used to adjust the minimum FCK/PCK ratio.
|
||||
|
||||
With this you can make sure that DISPC FCK is at least
|
||||
n x PCK. Video plane scaling requires higher FCK than
|
||||
normally.
|
||||
|
||||
If this is set to 0, there's no extra constraint on the
|
||||
DISPC FCK. However, the FCK will at minimum be
|
||||
2xPCK (if active matrix) or 3xPCK (if passive matrix).
|
||||
|
||||
Max FCK is 173MHz, so this doesn't work if your PCK
|
||||
is very high.
|
||||
|
||||
endif
|
6
drivers/video/omap2/dss/Makefile
Normal file
6
drivers/video/omap2/dss/Makefile
Normal file
@ -0,0 +1,6 @@
|
||||
obj-$(CONFIG_OMAP2_DSS) += omapdss.o
|
||||
omapdss-y := core.o dss.o dispc.o dpi.o display.o manager.o overlay.o
|
||||
omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o
|
||||
omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o
|
||||
omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o
|
||||
omapdss-$(CONFIG_OMAP2_DSS_DSI) += dsi.o
|
919
drivers/video/omap2/dss/core.c
Normal file
919
drivers/video/omap2/dss/core.c
Normal file
@ -0,0 +1,919 @@
|
||||
/*
|
||||
* linux/drivers/video/omap2/dss/core.c
|
||||
*
|
||||
* Copyright (C) 2009 Nokia Corporation
|
||||
* Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
|
||||
*
|
||||
* Some code and ideas taken from drivers/video/omap/ driver
|
||||
* by Imre Deak.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define DSS_SUBSYS_NAME "CORE"
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
#include <plat/display.h>
|
||||
#include <plat/clock.h>
|
||||
|
||||
#include "dss.h"
|
||||
|
||||
static struct {
|
||||
struct platform_device *pdev;
|
||||
int ctx_id;
|
||||
|
||||
struct clk *dss_ick;
|
||||
struct clk *dss1_fck;
|
||||
struct clk *dss2_fck;
|
||||
struct clk *dss_54m_fck;
|
||||
struct clk *dss_96m_fck;
|
||||
unsigned num_clks_enabled;
|
||||
} core;
|
||||
|
||||
static void dss_clk_enable_all_no_ctx(void);
|
||||
static void dss_clk_disable_all_no_ctx(void);
|
||||
static void dss_clk_enable_no_ctx(enum dss_clock clks);
|
||||
static void dss_clk_disable_no_ctx(enum dss_clock clks);
|
||||
|
||||
static char *def_disp_name;
|
||||
module_param_named(def_disp, def_disp_name, charp, 0);
|
||||
MODULE_PARM_DESC(def_disp_name, "default display name");
|
||||
|
||||
#ifdef DEBUG
|
||||
unsigned int dss_debug;
|
||||
module_param_named(debug, dss_debug, bool, 0644);
|
||||
#endif
|
||||
|
||||
/* CONTEXT */
|
||||
static int dss_get_ctx_id(void)
|
||||
{
|
||||
struct omap_dss_board_info *pdata = core.pdev->dev.platform_data;
|
||||
int r;
|
||||
|
||||
if (!pdata->get_last_off_on_transaction_id)
|
||||
return 0;
|
||||
r = pdata->get_last_off_on_transaction_id(&core.pdev->dev);
|
||||
if (r < 0) {
|
||||
dev_err(&core.pdev->dev, "getting transaction ID failed, "
|
||||
"will force context restore\n");
|
||||
r = -1;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
int dss_need_ctx_restore(void)
|
||||
{
|
||||
int id = dss_get_ctx_id();
|
||||
|
||||
if (id < 0 || id != core.ctx_id) {
|
||||
DSSDBG("ctx id %d -> id %d\n",
|
||||
core.ctx_id, id);
|
||||
core.ctx_id = id;
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void save_all_ctx(void)
|
||||
{
|
||||
DSSDBG("save context\n");
|
||||
|
||||
dss_clk_enable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK1);
|
||||
|
||||
dss_save_context();
|
||||
dispc_save_context();
|
||||
#ifdef CONFIG_OMAP2_DSS_DSI
|
||||
dsi_save_context();
|
||||
#endif
|
||||
|
||||
dss_clk_disable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK1);
|
||||
}
|
||||
|
||||
static void restore_all_ctx(void)
|
||||
{
|
||||
DSSDBG("restore context\n");
|
||||
|
||||
dss_clk_enable_all_no_ctx();
|
||||
|
||||
dss_restore_context();
|
||||
dispc_restore_context();
|
||||
#ifdef CONFIG_OMAP2_DSS_DSI
|
||||
dsi_restore_context();
|
||||
#endif
|
||||
|
||||
dss_clk_disable_all_no_ctx();
|
||||
}
|
||||
|
||||
/* CLOCKS */
|
||||
static void core_dump_clocks(struct seq_file *s)
|
||||
{
|
||||
int i;
|
||||
struct clk *clocks[5] = {
|
||||
core.dss_ick,
|
||||
core.dss1_fck,
|
||||
core.dss2_fck,
|
||||
core.dss_54m_fck,
|
||||
core.dss_96m_fck
|
||||
};
|
||||
|
||||
seq_printf(s, "- CORE -\n");
|
||||
|
||||
seq_printf(s, "internal clk count\t\t%u\n", core.num_clks_enabled);
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
if (!clocks[i])
|
||||
continue;
|
||||
seq_printf(s, "%-15s\t%lu\t%d\n",
|
||||
clocks[i]->name,
|
||||
clk_get_rate(clocks[i]),
|
||||
clocks[i]->usecount);
|
||||
}
|
||||
}
|
||||
|
||||
static int dss_get_clock(struct clk **clock, const char *clk_name)
|
||||
{
|
||||
struct clk *clk;
|
||||
|
||||
clk = clk_get(&core.pdev->dev, clk_name);
|
||||
|
||||
if (IS_ERR(clk)) {
|
||||
DSSERR("can't get clock %s", clk_name);
|
||||
return PTR_ERR(clk);
|
||||
}
|
||||
|
||||
*clock = clk;
|
||||
|
||||
DSSDBG("clk %s, rate %ld\n", clk_name, clk_get_rate(clk));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dss_get_clocks(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
core.dss_ick = NULL;
|
||||
core.dss1_fck = NULL;
|
||||
core.dss2_fck = NULL;
|
||||
core.dss_54m_fck = NULL;
|
||||
core.dss_96m_fck = NULL;
|
||||
|
||||
r = dss_get_clock(&core.dss_ick, "ick");
|
||||
if (r)
|
||||
goto err;
|
||||
|
||||
r = dss_get_clock(&core.dss1_fck, "dss1_fck");
|
||||
if (r)
|
||||
goto err;
|
||||
|
||||
r = dss_get_clock(&core.dss2_fck, "dss2_fck");
|
||||
if (r)
|
||||
goto err;
|
||||
|
||||
r = dss_get_clock(&core.dss_54m_fck, "tv_fck");
|
||||
if (r)
|
||||
goto err;
|
||||
|
||||
r = dss_get_clock(&core.dss_96m_fck, "video_fck");
|
||||
if (r)
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
if (core.dss_ick)
|
||||
clk_put(core.dss_ick);
|
||||
if (core.dss1_fck)
|
||||
clk_put(core.dss1_fck);
|
||||
if (core.dss2_fck)
|
||||
clk_put(core.dss2_fck);
|
||||
if (core.dss_54m_fck)
|
||||
clk_put(core.dss_54m_fck);
|
||||
if (core.dss_96m_fck)
|
||||
clk_put(core.dss_96m_fck);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void dss_put_clocks(void)
|
||||
{
|
||||
if (core.dss_96m_fck)
|
||||
clk_put(core.dss_96m_fck);
|
||||
clk_put(core.dss_54m_fck);
|
||||
clk_put(core.dss1_fck);
|
||||
clk_put(core.dss2_fck);
|
||||
clk_put(core.dss_ick);
|
||||
}
|
||||
|
||||
unsigned long dss_clk_get_rate(enum dss_clock clk)
|
||||
{
|
||||
switch (clk) {
|
||||
case DSS_CLK_ICK:
|
||||
return clk_get_rate(core.dss_ick);
|
||||
case DSS_CLK_FCK1:
|
||||
return clk_get_rate(core.dss1_fck);
|
||||
case DSS_CLK_FCK2:
|
||||
return clk_get_rate(core.dss2_fck);
|
||||
case DSS_CLK_54M:
|
||||
return clk_get_rate(core.dss_54m_fck);
|
||||
case DSS_CLK_96M:
|
||||
return clk_get_rate(core.dss_96m_fck);
|
||||
}
|
||||
|
||||
BUG();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned count_clk_bits(enum dss_clock clks)
|
||||
{
|
||||
unsigned num_clks = 0;
|
||||
|
||||
if (clks & DSS_CLK_ICK)
|
||||
++num_clks;
|
||||
if (clks & DSS_CLK_FCK1)
|
||||
++num_clks;
|
||||
if (clks & DSS_CLK_FCK2)
|
||||
++num_clks;
|
||||
if (clks & DSS_CLK_54M)
|
||||
++num_clks;
|
||||
if (clks & DSS_CLK_96M)
|
||||
++num_clks;
|
||||
|
||||
return num_clks;
|
||||
}
|
||||
|
||||
static void dss_clk_enable_no_ctx(enum dss_clock clks)
|
||||
{
|
||||
unsigned num_clks = count_clk_bits(clks);
|
||||
|
||||
if (clks & DSS_CLK_ICK)
|
||||
clk_enable(core.dss_ick);
|
||||
if (clks & DSS_CLK_FCK1)
|
||||
clk_enable(core.dss1_fck);
|
||||
if (clks & DSS_CLK_FCK2)
|
||||
clk_enable(core.dss2_fck);
|
||||
if (clks & DSS_CLK_54M)
|
||||
clk_enable(core.dss_54m_fck);
|
||||
if (clks & DSS_CLK_96M)
|
||||
clk_enable(core.dss_96m_fck);
|
||||
|
||||
core.num_clks_enabled += num_clks;
|
||||
}
|
||||
|
||||
void dss_clk_enable(enum dss_clock clks)
|
||||
{
|
||||
dss_clk_enable_no_ctx(clks);
|
||||
|
||||
if (cpu_is_omap34xx() && dss_need_ctx_restore())
|
||||
restore_all_ctx();
|
||||
}
|
||||
|
||||
static void dss_clk_disable_no_ctx(enum dss_clock clks)
|
||||
{
|
||||
unsigned num_clks = count_clk_bits(clks);
|
||||
|
||||
if (clks & DSS_CLK_ICK)
|
||||
clk_disable(core.dss_ick);
|
||||
if (clks & DSS_CLK_FCK1)
|
||||
clk_disable(core.dss1_fck);
|
||||
if (clks & DSS_CLK_FCK2)
|
||||
clk_disable(core.dss2_fck);
|
||||
if (clks & DSS_CLK_54M)
|
||||
clk_disable(core.dss_54m_fck);
|
||||
if (clks & DSS_CLK_96M)
|
||||
clk_disable(core.dss_96m_fck);
|
||||
|
||||
core.num_clks_enabled -= num_clks;
|
||||
}
|
||||
|
||||
void dss_clk_disable(enum dss_clock clks)
|
||||
{
|
||||
if (cpu_is_omap34xx()) {
|
||||
unsigned num_clks = count_clk_bits(clks);
|
||||
|
||||
BUG_ON(core.num_clks_enabled < num_clks);
|
||||
|
||||
if (core.num_clks_enabled == num_clks)
|
||||
save_all_ctx();
|
||||
}
|
||||
|
||||
dss_clk_disable_no_ctx(clks);
|
||||
}
|
||||
|
||||
static void dss_clk_enable_all_no_ctx(void)
|
||||
{
|
||||
enum dss_clock clks;
|
||||
|
||||
clks = DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_FCK2 | DSS_CLK_54M;
|
||||
if (cpu_is_omap34xx())
|
||||
clks |= DSS_CLK_96M;
|
||||
dss_clk_enable_no_ctx(clks);
|
||||
}
|
||||
|
||||
static void dss_clk_disable_all_no_ctx(void)
|
||||
{
|
||||
enum dss_clock clks;
|
||||
|
||||
clks = DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_FCK2 | DSS_CLK_54M;
|
||||
if (cpu_is_omap34xx())
|
||||
clks |= DSS_CLK_96M;
|
||||
dss_clk_disable_no_ctx(clks);
|
||||
}
|
||||
|
||||
static void dss_clk_disable_all(void)
|
||||
{
|
||||
enum dss_clock clks;
|
||||
|
||||
clks = DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_FCK2 | DSS_CLK_54M;
|
||||
if (cpu_is_omap34xx())
|
||||
clks |= DSS_CLK_96M;
|
||||
dss_clk_disable(clks);
|
||||
}
|
||||
|
||||
/* DEBUGFS */
|
||||
#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
|
||||
static void dss_debug_dump_clocks(struct seq_file *s)
|
||||
{
|
||||
core_dump_clocks(s);
|
||||
dss_dump_clocks(s);
|
||||
dispc_dump_clocks(s);
|
||||
#ifdef CONFIG_OMAP2_DSS_DSI
|
||||
dsi_dump_clocks(s);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int dss_debug_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
void (*func)(struct seq_file *) = s->private;
|
||||
func(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dss_debug_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, dss_debug_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations dss_debug_fops = {
|
||||
.open = dss_debug_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static struct dentry *dss_debugfs_dir;
|
||||
|
||||
static int dss_initialize_debugfs(void)
|
||||
{
|
||||
dss_debugfs_dir = debugfs_create_dir("omapdss", NULL);
|
||||
if (IS_ERR(dss_debugfs_dir)) {
|
||||
int err = PTR_ERR(dss_debugfs_dir);
|
||||
dss_debugfs_dir = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
debugfs_create_file("clk", S_IRUGO, dss_debugfs_dir,
|
||||
&dss_debug_dump_clocks, &dss_debug_fops);
|
||||
|
||||
debugfs_create_file("dss", S_IRUGO, dss_debugfs_dir,
|
||||
&dss_dump_regs, &dss_debug_fops);
|
||||
debugfs_create_file("dispc", S_IRUGO, dss_debugfs_dir,
|
||||
&dispc_dump_regs, &dss_debug_fops);
|
||||
#ifdef CONFIG_OMAP2_DSS_RFBI
|
||||
debugfs_create_file("rfbi", S_IRUGO, dss_debugfs_dir,
|
||||
&rfbi_dump_regs, &dss_debug_fops);
|
||||
#endif
|
||||
#ifdef CONFIG_OMAP2_DSS_DSI
|
||||
debugfs_create_file("dsi", S_IRUGO, dss_debugfs_dir,
|
||||
&dsi_dump_regs, &dss_debug_fops);
|
||||
#endif
|
||||
#ifdef CONFIG_OMAP2_DSS_VENC
|
||||
debugfs_create_file("venc", S_IRUGO, dss_debugfs_dir,
|
||||
&venc_dump_regs, &dss_debug_fops);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dss_uninitialize_debugfs(void)
|
||||
{
|
||||
if (dss_debugfs_dir)
|
||||
debugfs_remove_recursive(dss_debugfs_dir);
|
||||
}
|
||||
#endif /* CONFIG_DEBUG_FS && CONFIG_OMAP2_DSS_DEBUG_SUPPORT */
|
||||
|
||||
/* PLATFORM DEVICE */
|
||||
static int omap_dss_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_dss_board_info *pdata = pdev->dev.platform_data;
|
||||
int skip_init = 0;
|
||||
int r;
|
||||
int i;
|
||||
|
||||
core.pdev = pdev;
|
||||
|
||||
dss_init_overlay_managers(pdev);
|
||||
dss_init_overlays(pdev);
|
||||
|
||||
r = dss_get_clocks();
|
||||
if (r)
|
||||
goto fail0;
|
||||
|
||||
dss_clk_enable_all_no_ctx();
|
||||
|
||||
core.ctx_id = dss_get_ctx_id();
|
||||
DSSDBG("initial ctx id %u\n", core.ctx_id);
|
||||
|
||||
#ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT
|
||||
/* DISPC_CONTROL */
|
||||
if (omap_readl(0x48050440) & 1) /* LCD enabled? */
|
||||
skip_init = 1;
|
||||
#endif
|
||||
|
||||
r = dss_init(skip_init);
|
||||
if (r) {
|
||||
DSSERR("Failed to initialize DSS\n");
|
||||
goto fail0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OMAP2_DSS_RFBI
|
||||
r = rfbi_init();
|
||||
if (r) {
|
||||
DSSERR("Failed to initialize rfbi\n");
|
||||
goto fail0;
|
||||
}
|
||||
#endif
|
||||
|
||||
r = dpi_init();
|
||||
if (r) {
|
||||
DSSERR("Failed to initialize dpi\n");
|
||||
goto fail0;
|
||||
}
|
||||
|
||||
r = dispc_init();
|
||||
if (r) {
|
||||
DSSERR("Failed to initialize dispc\n");
|
||||
goto fail0;
|
||||
}
|
||||
#ifdef CONFIG_OMAP2_DSS_VENC
|
||||
r = venc_init(pdev);
|
||||
if (r) {
|
||||
DSSERR("Failed to initialize venc\n");
|
||||
goto fail0;
|
||||
}
|
||||
#endif
|
||||
if (cpu_is_omap34xx()) {
|
||||
#ifdef CONFIG_OMAP2_DSS_SDI
|
||||
r = sdi_init(skip_init);
|
||||
if (r) {
|
||||
DSSERR("Failed to initialize SDI\n");
|
||||
goto fail0;
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_OMAP2_DSS_DSI
|
||||
r = dsi_init(pdev);
|
||||
if (r) {
|
||||
DSSERR("Failed to initialize DSI\n");
|
||||
goto fail0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
|
||||
r = dss_initialize_debugfs();
|
||||
if (r)
|
||||
goto fail0;
|
||||
#endif
|
||||
|
||||
for (i = 0; i < pdata->num_devices; ++i) {
|
||||
struct omap_dss_device *dssdev = pdata->devices[i];
|
||||
|
||||
r = omap_dss_register_device(dssdev);
|
||||
if (r)
|
||||
DSSERR("device reg failed %d\n", i);
|
||||
|
||||
if (def_disp_name && strcmp(def_disp_name, dssdev->name) == 0)
|
||||
pdata->default_device = dssdev;
|
||||
}
|
||||
|
||||
dss_clk_disable_all();
|
||||
|
||||
return 0;
|
||||
|
||||
/* XXX fail correctly */
|
||||
fail0:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int omap_dss_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_dss_board_info *pdata = pdev->dev.platform_data;
|
||||
int i;
|
||||
int c;
|
||||
|
||||
#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
|
||||
dss_uninitialize_debugfs();
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_OMAP2_DSS_VENC
|
||||
venc_exit();
|
||||
#endif
|
||||
dispc_exit();
|
||||
dpi_exit();
|
||||
#ifdef CONFIG_OMAP2_DSS_RFBI
|
||||
rfbi_exit();
|
||||
#endif
|
||||
if (cpu_is_omap34xx()) {
|
||||
#ifdef CONFIG_OMAP2_DSS_DSI
|
||||
dsi_exit();
|
||||
#endif
|
||||
#ifdef CONFIG_OMAP2_DSS_SDI
|
||||
sdi_exit();
|
||||
#endif
|
||||
}
|
||||
|
||||
dss_exit();
|
||||
|
||||
/* these should be removed at some point */
|
||||
c = core.dss_ick->usecount;
|
||||
if (c > 0) {
|
||||
DSSERR("warning: dss_ick usecount %d, disabling\n", c);
|
||||
while (c-- > 0)
|
||||
clk_disable(core.dss_ick);
|
||||
}
|
||||
|
||||
c = core.dss1_fck->usecount;
|
||||
if (c > 0) {
|
||||
DSSERR("warning: dss1_fck usecount %d, disabling\n", c);
|
||||
while (c-- > 0)
|
||||
clk_disable(core.dss1_fck);
|
||||
}
|
||||
|
||||
c = core.dss2_fck->usecount;
|
||||
if (c > 0) {
|
||||
DSSERR("warning: dss2_fck usecount %d, disabling\n", c);
|
||||
while (c-- > 0)
|
||||
clk_disable(core.dss2_fck);
|
||||
}
|
||||
|
||||
c = core.dss_54m_fck->usecount;
|
||||
if (c > 0) {
|
||||
DSSERR("warning: dss_54m_fck usecount %d, disabling\n", c);
|
||||
while (c-- > 0)
|
||||
clk_disable(core.dss_54m_fck);
|
||||
}
|
||||
|
||||
if (core.dss_96m_fck) {
|
||||
c = core.dss_96m_fck->usecount;
|
||||
if (c > 0) {
|
||||
DSSERR("warning: dss_96m_fck usecount %d, disabling\n",
|
||||
c);
|
||||
while (c-- > 0)
|
||||
clk_disable(core.dss_96m_fck);
|
||||
}
|
||||
}
|
||||
|
||||
dss_put_clocks();
|
||||
|
||||
dss_uninit_overlays(pdev);
|
||||
dss_uninit_overlay_managers(pdev);
|
||||
|
||||
for (i = 0; i < pdata->num_devices; ++i)
|
||||
omap_dss_unregister_device(pdata->devices[i]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void omap_dss_shutdown(struct platform_device *pdev)
|
||||
{
|
||||
DSSDBG("shutdown\n");
|
||||
dss_disable_all_devices();
|
||||
}
|
||||
|
||||
static int omap_dss_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
{
|
||||
DSSDBG("suspend %d\n", state.event);
|
||||
|
||||
return dss_suspend_all_devices();
|
||||
}
|
||||
|
||||
static int omap_dss_resume(struct platform_device *pdev)
|
||||
{
|
||||
DSSDBG("resume\n");
|
||||
|
||||
return dss_resume_all_devices();
|
||||
}
|
||||
|
||||
static struct platform_driver omap_dss_driver = {
|
||||
.probe = omap_dss_probe,
|
||||
.remove = omap_dss_remove,
|
||||
.shutdown = omap_dss_shutdown,
|
||||
.suspend = omap_dss_suspend,
|
||||
.resume = omap_dss_resume,
|
||||
.driver = {
|
||||
.name = "omapdss",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
/* BUS */
|
||||
static int dss_bus_match(struct device *dev, struct device_driver *driver)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
|
||||
DSSDBG("bus_match. dev %s/%s, drv %s\n",
|
||||
dev_name(dev), dssdev->driver_name, driver->name);
|
||||
|
||||
return strcmp(dssdev->driver_name, driver->name) == 0;
|
||||
}
|
||||
|
||||
static ssize_t device_name_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n",
|
||||
dssdev->name ?
|
||||
dssdev->name : "");
|
||||
}
|
||||
|
||||
static struct device_attribute default_dev_attrs[] = {
|
||||
__ATTR(name, S_IRUGO, device_name_show, NULL),
|
||||
__ATTR_NULL,
|
||||
};
|
||||
|
||||
static ssize_t driver_name_show(struct device_driver *drv, char *buf)
|
||||
{
|
||||
struct omap_dss_driver *dssdrv = to_dss_driver(drv);
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n",
|
||||
dssdrv->driver.name ?
|
||||
dssdrv->driver.name : "");
|
||||
}
|
||||
static struct driver_attribute default_drv_attrs[] = {
|
||||
__ATTR(name, S_IRUGO, driver_name_show, NULL),
|
||||
__ATTR_NULL,
|
||||
};
|
||||
|
||||
static struct bus_type dss_bus_type = {
|
||||
.name = "omapdss",
|
||||
.match = dss_bus_match,
|
||||
.dev_attrs = default_dev_attrs,
|
||||
.drv_attrs = default_drv_attrs,
|
||||
};
|
||||
|
||||
static void dss_bus_release(struct device *dev)
|
||||
{
|
||||
DSSDBG("bus_release\n");
|
||||
}
|
||||
|
||||
static struct device dss_bus = {
|
||||
.release = dss_bus_release,
|
||||
};
|
||||
|
||||
struct bus_type *dss_get_bus(void)
|
||||
{
|
||||
return &dss_bus_type;
|
||||
}
|
||||
|
||||
/* DRIVER */
|
||||
static int dss_driver_probe(struct device *dev)
|
||||
{
|
||||
int r;
|
||||
struct omap_dss_driver *dssdrv = to_dss_driver(dev->driver);
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
struct omap_dss_board_info *pdata = core.pdev->dev.platform_data;
|
||||
bool force;
|
||||
|
||||
DSSDBG("driver_probe: dev %s/%s, drv %s\n",
|
||||
dev_name(dev), dssdev->driver_name,
|
||||
dssdrv->driver.name);
|
||||
|
||||
dss_init_device(core.pdev, dssdev);
|
||||
|
||||
/* skip this if the device is behind a ctrl */
|
||||
if (!dssdev->panel.ctrl) {
|
||||
force = pdata->default_device == dssdev;
|
||||
dss_recheck_connections(dssdev, force);
|
||||
}
|
||||
|
||||
r = dssdrv->probe(dssdev);
|
||||
|
||||
if (r) {
|
||||
DSSERR("driver probe failed: %d\n", r);
|
||||
return r;
|
||||
}
|
||||
|
||||
DSSDBG("probe done for device %s\n", dev_name(dev));
|
||||
|
||||
dssdev->driver = dssdrv;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dss_driver_remove(struct device *dev)
|
||||
{
|
||||
struct omap_dss_driver *dssdrv = to_dss_driver(dev->driver);
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
|
||||
DSSDBG("driver_remove: dev %s/%s\n", dev_name(dev),
|
||||
dssdev->driver_name);
|
||||
|
||||
dssdrv->remove(dssdev);
|
||||
|
||||
dss_uninit_device(core.pdev, dssdev);
|
||||
|
||||
dssdev->driver = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int omap_dss_register_driver(struct omap_dss_driver *dssdriver)
|
||||
{
|
||||
dssdriver->driver.bus = &dss_bus_type;
|
||||
dssdriver->driver.probe = dss_driver_probe;
|
||||
dssdriver->driver.remove = dss_driver_remove;
|
||||
return driver_register(&dssdriver->driver);
|
||||
}
|
||||
EXPORT_SYMBOL(omap_dss_register_driver);
|
||||
|
||||
void omap_dss_unregister_driver(struct omap_dss_driver *dssdriver)
|
||||
{
|
||||
driver_unregister(&dssdriver->driver);
|
||||
}
|
||||
EXPORT_SYMBOL(omap_dss_unregister_driver);
|
||||
|
||||
/* DEVICE */
|
||||
static void reset_device(struct device *dev, int check)
|
||||
{
|
||||
u8 *dev_p = (u8 *)dev;
|
||||
u8 *dev_end = dev_p + sizeof(*dev);
|
||||
void *saved_pdata;
|
||||
|
||||
saved_pdata = dev->platform_data;
|
||||
if (check) {
|
||||
/*
|
||||
* Check if there is any other setting than platform_data
|
||||
* in struct device; warn that these will be reset by our
|
||||
* init.
|
||||
*/
|
||||
dev->platform_data = NULL;
|
||||
while (dev_p < dev_end) {
|
||||
if (*dev_p) {
|
||||
WARN("%s: struct device fields will be "
|
||||
"discarded\n",
|
||||
__func__);
|
||||
break;
|
||||
}
|
||||
dev_p++;
|
||||
}
|
||||
}
|
||||
memset(dev, 0, sizeof(*dev));
|
||||
dev->platform_data = saved_pdata;
|
||||
}
|
||||
|
||||
|
||||
static void omap_dss_dev_release(struct device *dev)
|
||||
{
|
||||
reset_device(dev, 0);
|
||||
}
|
||||
|
||||
int omap_dss_register_device(struct omap_dss_device *dssdev)
|
||||
{
|
||||
static int dev_num;
|
||||
static int panel_num;
|
||||
int r;
|
||||
|
||||
WARN_ON(!dssdev->driver_name);
|
||||
|
||||
reset_device(&dssdev->dev, 1);
|
||||
dssdev->dev.bus = &dss_bus_type;
|
||||
dssdev->dev.parent = &dss_bus;
|
||||
dssdev->dev.release = omap_dss_dev_release;
|
||||
dev_set_name(&dssdev->dev, "display%d", dev_num++);
|
||||
r = device_register(&dssdev->dev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (dssdev->ctrl.panel) {
|
||||
struct omap_dss_device *panel = dssdev->ctrl.panel;
|
||||
|
||||
panel->panel.ctrl = dssdev;
|
||||
|
||||
reset_device(&panel->dev, 1);
|
||||
panel->dev.bus = &dss_bus_type;
|
||||
panel->dev.parent = &dssdev->dev;
|
||||
panel->dev.release = omap_dss_dev_release;
|
||||
dev_set_name(&panel->dev, "panel%d", panel_num++);
|
||||
r = device_register(&panel->dev);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void omap_dss_unregister_device(struct omap_dss_device *dssdev)
|
||||
{
|
||||
device_unregister(&dssdev->dev);
|
||||
|
||||
if (dssdev->ctrl.panel) {
|
||||
struct omap_dss_device *panel = dssdev->ctrl.panel;
|
||||
device_unregister(&panel->dev);
|
||||
}
|
||||
}
|
||||
|
||||
/* BUS */
|
||||
static int omap_dss_bus_register(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = bus_register(&dss_bus_type);
|
||||
if (r) {
|
||||
DSSERR("bus register failed\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
dev_set_name(&dss_bus, "omapdss");
|
||||
r = device_register(&dss_bus);
|
||||
if (r) {
|
||||
DSSERR("bus driver register failed\n");
|
||||
bus_unregister(&dss_bus_type);
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* INIT */
|
||||
|
||||
#ifdef CONFIG_OMAP2_DSS_MODULE
|
||||
static void omap_dss_bus_unregister(void)
|
||||
{
|
||||
device_unregister(&dss_bus);
|
||||
|
||||
bus_unregister(&dss_bus_type);
|
||||
}
|
||||
|
||||
static int __init omap_dss_init(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = omap_dss_bus_register();
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = platform_driver_register(&omap_dss_driver);
|
||||
if (r) {
|
||||
omap_dss_bus_unregister();
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit omap_dss_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&omap_dss_driver);
|
||||
|
||||
omap_dss_bus_unregister();
|
||||
}
|
||||
|
||||
module_init(omap_dss_init);
|
||||
module_exit(omap_dss_exit);
|
||||
#else
|
||||
static int __init omap_dss_init(void)
|
||||
{
|
||||
return omap_dss_bus_register();
|
||||
}
|
||||
|
||||
static int __init omap_dss_init2(void)
|
||||
{
|
||||
return platform_driver_register(&omap_dss_driver);
|
||||
}
|
||||
|
||||
core_initcall(omap_dss_init);
|
||||
device_initcall(omap_dss_init2);
|
||||
#endif
|
||||
|
||||
MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>");
|
||||
MODULE_DESCRIPTION("OMAP2/3 Display Subsystem");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
3091
drivers/video/omap2/dss/dispc.c
Normal file
3091
drivers/video/omap2/dss/dispc.c
Normal file
File diff suppressed because it is too large
Load Diff
671
drivers/video/omap2/dss/display.c
Normal file
671
drivers/video/omap2/dss/display.c
Normal file
@ -0,0 +1,671 @@
|
||||
/*
|
||||
* linux/drivers/video/omap2/dss/display.c
|
||||
*
|
||||
* Copyright (C) 2009 Nokia Corporation
|
||||
* Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
|
||||
*
|
||||
* Some code and ideas taken from drivers/video/omap/ driver
|
||||
* by Imre Deak.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define DSS_SUBSYS_NAME "DISPLAY"
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <plat/display.h>
|
||||
#include "dss.h"
|
||||
|
||||
static LIST_HEAD(display_list);
|
||||
|
||||
static ssize_t display_enabled_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
bool enabled = dssdev->state != OMAP_DSS_DISPLAY_DISABLED;
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", enabled);
|
||||
}
|
||||
|
||||
static ssize_t display_enabled_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
bool enabled, r;
|
||||
|
||||
enabled = simple_strtoul(buf, NULL, 10);
|
||||
|
||||
if (enabled != (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)) {
|
||||
if (enabled) {
|
||||
r = dssdev->enable(dssdev);
|
||||
if (r)
|
||||
return r;
|
||||
} else {
|
||||
dssdev->disable(dssdev);
|
||||
}
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t display_upd_mode_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
enum omap_dss_update_mode mode = OMAP_DSS_UPDATE_AUTO;
|
||||
if (dssdev->get_update_mode)
|
||||
mode = dssdev->get_update_mode(dssdev);
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", mode);
|
||||
}
|
||||
|
||||
static ssize_t display_upd_mode_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
int val, r;
|
||||
enum omap_dss_update_mode mode;
|
||||
|
||||
val = simple_strtoul(buf, NULL, 10);
|
||||
|
||||
switch (val) {
|
||||
case OMAP_DSS_UPDATE_DISABLED:
|
||||
case OMAP_DSS_UPDATE_AUTO:
|
||||
case OMAP_DSS_UPDATE_MANUAL:
|
||||
mode = (enum omap_dss_update_mode)val;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = dssdev->set_update_mode(dssdev, mode);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t display_tear_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n",
|
||||
dssdev->get_te ? dssdev->get_te(dssdev) : 0);
|
||||
}
|
||||
|
||||
static ssize_t display_tear_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t size)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
unsigned long te;
|
||||
int r;
|
||||
|
||||
if (!dssdev->enable_te || !dssdev->get_te)
|
||||
return -ENOENT;
|
||||
|
||||
te = simple_strtoul(buf, NULL, 0);
|
||||
|
||||
r = dssdev->enable_te(dssdev, te);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t display_timings_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
struct omap_video_timings t;
|
||||
|
||||
if (!dssdev->get_timings)
|
||||
return -ENOENT;
|
||||
|
||||
dssdev->get_timings(dssdev, &t);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%u,%u/%u/%u/%u,%u/%u/%u/%u\n",
|
||||
t.pixel_clock,
|
||||
t.x_res, t.hfp, t.hbp, t.hsw,
|
||||
t.y_res, t.vfp, t.vbp, t.vsw);
|
||||
}
|
||||
|
||||
static ssize_t display_timings_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t size)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
struct omap_video_timings t;
|
||||
int r, found;
|
||||
|
||||
if (!dssdev->set_timings || !dssdev->check_timings)
|
||||
return -ENOENT;
|
||||
|
||||
found = 0;
|
||||
#ifdef CONFIG_OMAP2_DSS_VENC
|
||||
if (strncmp("pal", buf, 3) == 0) {
|
||||
t = omap_dss_pal_timings;
|
||||
found = 1;
|
||||
} else if (strncmp("ntsc", buf, 4) == 0) {
|
||||
t = omap_dss_ntsc_timings;
|
||||
found = 1;
|
||||
}
|
||||
#endif
|
||||
if (!found && sscanf(buf, "%u,%hu/%hu/%hu/%hu,%hu/%hu/%hu/%hu",
|
||||
&t.pixel_clock,
|
||||
&t.x_res, &t.hfp, &t.hbp, &t.hsw,
|
||||
&t.y_res, &t.vfp, &t.vbp, &t.vsw) != 9)
|
||||
return -EINVAL;
|
||||
|
||||
r = dssdev->check_timings(dssdev, &t);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dssdev->set_timings(dssdev, &t);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t display_rotate_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
int rotate;
|
||||
if (!dssdev->get_rotate)
|
||||
return -ENOENT;
|
||||
rotate = dssdev->get_rotate(dssdev);
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", rotate);
|
||||
}
|
||||
|
||||
static ssize_t display_rotate_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t size)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
unsigned long rot;
|
||||
int r;
|
||||
|
||||
if (!dssdev->set_rotate || !dssdev->get_rotate)
|
||||
return -ENOENT;
|
||||
|
||||
rot = simple_strtoul(buf, NULL, 0);
|
||||
|
||||
r = dssdev->set_rotate(dssdev, rot);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t display_mirror_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
int mirror;
|
||||
if (!dssdev->get_mirror)
|
||||
return -ENOENT;
|
||||
mirror = dssdev->get_mirror(dssdev);
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", mirror);
|
||||
}
|
||||
|
||||
static ssize_t display_mirror_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t size)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
unsigned long mirror;
|
||||
int r;
|
||||
|
||||
if (!dssdev->set_mirror || !dssdev->get_mirror)
|
||||
return -ENOENT;
|
||||
|
||||
mirror = simple_strtoul(buf, NULL, 0);
|
||||
|
||||
r = dssdev->set_mirror(dssdev, mirror);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t display_wss_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
unsigned int wss;
|
||||
|
||||
if (!dssdev->get_wss)
|
||||
return -ENOENT;
|
||||
|
||||
wss = dssdev->get_wss(dssdev);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "0x%05x\n", wss);
|
||||
}
|
||||
|
||||
static ssize_t display_wss_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t size)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
unsigned long wss;
|
||||
int r;
|
||||
|
||||
if (!dssdev->get_wss || !dssdev->set_wss)
|
||||
return -ENOENT;
|
||||
|
||||
if (strict_strtoul(buf, 0, &wss))
|
||||
return -EINVAL;
|
||||
|
||||
if (wss > 0xfffff)
|
||||
return -EINVAL;
|
||||
|
||||
r = dssdev->set_wss(dssdev, wss);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(enabled, S_IRUGO|S_IWUSR,
|
||||
display_enabled_show, display_enabled_store);
|
||||
static DEVICE_ATTR(update_mode, S_IRUGO|S_IWUSR,
|
||||
display_upd_mode_show, display_upd_mode_store);
|
||||
static DEVICE_ATTR(tear_elim, S_IRUGO|S_IWUSR,
|
||||
display_tear_show, display_tear_store);
|
||||
static DEVICE_ATTR(timings, S_IRUGO|S_IWUSR,
|
||||
display_timings_show, display_timings_store);
|
||||
static DEVICE_ATTR(rotate, S_IRUGO|S_IWUSR,
|
||||
display_rotate_show, display_rotate_store);
|
||||
static DEVICE_ATTR(mirror, S_IRUGO|S_IWUSR,
|
||||
display_mirror_show, display_mirror_store);
|
||||
static DEVICE_ATTR(wss, S_IRUGO|S_IWUSR,
|
||||
display_wss_show, display_wss_store);
|
||||
|
||||
static struct device_attribute *display_sysfs_attrs[] = {
|
||||
&dev_attr_enabled,
|
||||
&dev_attr_update_mode,
|
||||
&dev_attr_tear_elim,
|
||||
&dev_attr_timings,
|
||||
&dev_attr_rotate,
|
||||
&dev_attr_mirror,
|
||||
&dev_attr_wss,
|
||||
NULL
|
||||
};
|
||||
|
||||
static void default_get_resolution(struct omap_dss_device *dssdev,
|
||||
u16 *xres, u16 *yres)
|
||||
{
|
||||
*xres = dssdev->panel.timings.x_res;
|
||||
*yres = dssdev->panel.timings.y_res;
|
||||
}
|
||||
|
||||
void default_get_overlay_fifo_thresholds(enum omap_plane plane,
|
||||
u32 fifo_size, enum omap_burst_size *burst_size,
|
||||
u32 *fifo_low, u32 *fifo_high)
|
||||
{
|
||||
unsigned burst_size_bytes;
|
||||
|
||||
*burst_size = OMAP_DSS_BURST_16x32;
|
||||
burst_size_bytes = 16 * 32 / 8;
|
||||
|
||||
*fifo_high = fifo_size - 1;
|
||||
*fifo_low = fifo_size - burst_size_bytes;
|
||||
}
|
||||
|
||||
static int default_wait_vsync(struct omap_dss_device *dssdev)
|
||||
{
|
||||
unsigned long timeout = msecs_to_jiffies(500);
|
||||
u32 irq;
|
||||
|
||||
if (dssdev->type == OMAP_DISPLAY_TYPE_VENC)
|
||||
irq = DISPC_IRQ_EVSYNC_ODD;
|
||||
else
|
||||
irq = DISPC_IRQ_VSYNC;
|
||||
|
||||
return omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
|
||||
}
|
||||
|
||||
static int default_get_recommended_bpp(struct omap_dss_device *dssdev)
|
||||
{
|
||||
if (dssdev->panel.recommended_bpp)
|
||||
return dssdev->panel.recommended_bpp;
|
||||
|
||||
switch (dssdev->type) {
|
||||
case OMAP_DISPLAY_TYPE_DPI:
|
||||
if (dssdev->phy.dpi.data_lines == 24)
|
||||
return 24;
|
||||
else
|
||||
return 16;
|
||||
|
||||
case OMAP_DISPLAY_TYPE_DBI:
|
||||
case OMAP_DISPLAY_TYPE_DSI:
|
||||
if (dssdev->ctrl.pixel_size == 24)
|
||||
return 24;
|
||||
else
|
||||
return 16;
|
||||
case OMAP_DISPLAY_TYPE_VENC:
|
||||
case OMAP_DISPLAY_TYPE_SDI:
|
||||
return 24;
|
||||
return 24;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
|
||||
/* Checks if replication logic should be used. Only use for active matrix,
|
||||
* when overlay is in RGB12U or RGB16 mode, and LCD interface is
|
||||
* 18bpp or 24bpp */
|
||||
bool dss_use_replication(struct omap_dss_device *dssdev,
|
||||
enum omap_color_mode mode)
|
||||
{
|
||||
int bpp;
|
||||
|
||||
if (mode != OMAP_DSS_COLOR_RGB12U && mode != OMAP_DSS_COLOR_RGB16)
|
||||
return false;
|
||||
|
||||
if (dssdev->type == OMAP_DISPLAY_TYPE_DPI &&
|
||||
(dssdev->panel.config & OMAP_DSS_LCD_TFT) == 0)
|
||||
return false;
|
||||
|
||||
switch (dssdev->type) {
|
||||
case OMAP_DISPLAY_TYPE_DPI:
|
||||
bpp = dssdev->phy.dpi.data_lines;
|
||||
break;
|
||||
case OMAP_DISPLAY_TYPE_VENC:
|
||||
case OMAP_DISPLAY_TYPE_SDI:
|
||||
bpp = 24;
|
||||
break;
|
||||
case OMAP_DISPLAY_TYPE_DBI:
|
||||
case OMAP_DISPLAY_TYPE_DSI:
|
||||
bpp = dssdev->ctrl.pixel_size;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
||||
return bpp > 16;
|
||||
}
|
||||
|
||||
void dss_init_device(struct platform_device *pdev,
|
||||
struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct device_attribute *attr;
|
||||
int i;
|
||||
int r;
|
||||
|
||||
switch (dssdev->type) {
|
||||
case OMAP_DISPLAY_TYPE_DPI:
|
||||
#ifdef CONFIG_OMAP2_DSS_RFBI
|
||||
case OMAP_DISPLAY_TYPE_DBI:
|
||||
#endif
|
||||
#ifdef CONFIG_OMAP2_DSS_SDI
|
||||
case OMAP_DISPLAY_TYPE_SDI:
|
||||
#endif
|
||||
#ifdef CONFIG_OMAP2_DSS_DSI
|
||||
case OMAP_DISPLAY_TYPE_DSI:
|
||||
#endif
|
||||
#ifdef CONFIG_OMAP2_DSS_VENC
|
||||
case OMAP_DISPLAY_TYPE_VENC:
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
DSSERR("Support for display '%s' not compiled in.\n",
|
||||
dssdev->name);
|
||||
return;
|
||||
}
|
||||
|
||||
dssdev->get_resolution = default_get_resolution;
|
||||
dssdev->get_recommended_bpp = default_get_recommended_bpp;
|
||||
dssdev->wait_vsync = default_wait_vsync;
|
||||
|
||||
switch (dssdev->type) {
|
||||
case OMAP_DISPLAY_TYPE_DPI:
|
||||
r = dpi_init_display(dssdev);
|
||||
break;
|
||||
#ifdef CONFIG_OMAP2_DSS_RFBI
|
||||
case OMAP_DISPLAY_TYPE_DBI:
|
||||
r = rfbi_init_display(dssdev);
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_OMAP2_DSS_VENC
|
||||
case OMAP_DISPLAY_TYPE_VENC:
|
||||
r = venc_init_display(dssdev);
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_OMAP2_DSS_SDI
|
||||
case OMAP_DISPLAY_TYPE_SDI:
|
||||
r = sdi_init_display(dssdev);
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_OMAP2_DSS_DSI
|
||||
case OMAP_DISPLAY_TYPE_DSI:
|
||||
r = dsi_init_display(dssdev);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
||||
if (r) {
|
||||
DSSERR("failed to init display %s\n", dssdev->name);
|
||||
return;
|
||||
}
|
||||
|
||||
/* create device sysfs files */
|
||||
i = 0;
|
||||
while ((attr = display_sysfs_attrs[i++]) != NULL) {
|
||||
r = device_create_file(&dssdev->dev, attr);
|
||||
if (r)
|
||||
DSSERR("failed to create sysfs file\n");
|
||||
}
|
||||
|
||||
/* create display? sysfs links */
|
||||
r = sysfs_create_link(&pdev->dev.kobj, &dssdev->dev.kobj,
|
||||
dev_name(&dssdev->dev));
|
||||
if (r)
|
||||
DSSERR("failed to create sysfs display link\n");
|
||||
}
|
||||
|
||||
void dss_uninit_device(struct platform_device *pdev,
|
||||
struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct device_attribute *attr;
|
||||
int i = 0;
|
||||
|
||||
sysfs_remove_link(&pdev->dev.kobj, dev_name(&dssdev->dev));
|
||||
|
||||
while ((attr = display_sysfs_attrs[i++]) != NULL)
|
||||
device_remove_file(&dssdev->dev, attr);
|
||||
|
||||
if (dssdev->manager)
|
||||
dssdev->manager->unset_device(dssdev->manager);
|
||||
}
|
||||
|
||||
static int dss_suspend_device(struct device *dev, void *data)
|
||||
{
|
||||
int r;
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
|
||||
if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
|
||||
dssdev->activate_after_resume = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!dssdev->suspend) {
|
||||
DSSERR("display '%s' doesn't implement suspend\n",
|
||||
dssdev->name);
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
r = dssdev->suspend(dssdev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dssdev->activate_after_resume = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dss_suspend_all_devices(void)
|
||||
{
|
||||
int r;
|
||||
struct bus_type *bus = dss_get_bus();
|
||||
|
||||
r = bus_for_each_dev(bus, NULL, NULL, dss_suspend_device);
|
||||
if (r) {
|
||||
/* resume all displays that were suspended */
|
||||
dss_resume_all_devices();
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dss_resume_device(struct device *dev, void *data)
|
||||
{
|
||||
int r;
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
|
||||
if (dssdev->activate_after_resume && dssdev->resume) {
|
||||
r = dssdev->resume(dssdev);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
dssdev->activate_after_resume = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dss_resume_all_devices(void)
|
||||
{
|
||||
struct bus_type *bus = dss_get_bus();
|
||||
|
||||
return bus_for_each_dev(bus, NULL, NULL, dss_resume_device);
|
||||
}
|
||||
|
||||
static int dss_disable_device(struct device *dev, void *data)
|
||||
{
|
||||
struct omap_dss_device *dssdev = to_dss_device(dev);
|
||||
dssdev->disable(dssdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dss_disable_all_devices(void)
|
||||
{
|
||||
struct bus_type *bus = dss_get_bus();
|
||||
bus_for_each_dev(bus, NULL, NULL, dss_disable_device);
|
||||
}
|
||||
|
||||
|
||||
void omap_dss_get_device(struct omap_dss_device *dssdev)
|
||||
{
|
||||
get_device(&dssdev->dev);
|
||||
}
|
||||
EXPORT_SYMBOL(omap_dss_get_device);
|
||||
|
||||
void omap_dss_put_device(struct omap_dss_device *dssdev)
|
||||
{
|
||||
put_device(&dssdev->dev);
|
||||
}
|
||||
EXPORT_SYMBOL(omap_dss_put_device);
|
||||
|
||||
/* ref count of the found device is incremented. ref count
|
||||
* of from-device is decremented. */
|
||||
struct omap_dss_device *omap_dss_get_next_device(struct omap_dss_device *from)
|
||||
{
|
||||
struct device *dev;
|
||||
struct device *dev_start = NULL;
|
||||
struct omap_dss_device *dssdev = NULL;
|
||||
|
||||
int match(struct device *dev, void *data)
|
||||
{
|
||||
/* skip panels connected to controllers */
|
||||
if (to_dss_device(dev)->panel.ctrl)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (from)
|
||||
dev_start = &from->dev;
|
||||
dev = bus_find_device(dss_get_bus(), dev_start, NULL, match);
|
||||
if (dev)
|
||||
dssdev = to_dss_device(dev);
|
||||
if (from)
|
||||
put_device(&from->dev);
|
||||
|
||||
return dssdev;
|
||||
}
|
||||
EXPORT_SYMBOL(omap_dss_get_next_device);
|
||||
|
||||
struct omap_dss_device *omap_dss_find_device(void *data,
|
||||
int (*match)(struct omap_dss_device *dssdev, void *data))
|
||||
{
|
||||
struct omap_dss_device *dssdev = NULL;
|
||||
|
||||
while ((dssdev = omap_dss_get_next_device(dssdev)) != NULL) {
|
||||
if (match(dssdev, data))
|
||||
return dssdev;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(omap_dss_find_device);
|
||||
|
||||
int omap_dss_start_device(struct omap_dss_device *dssdev)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (!dssdev->driver) {
|
||||
DSSDBG("no driver\n");
|
||||
r = -ENODEV;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
if (dssdev->ctrl.panel && !dssdev->ctrl.panel->driver) {
|
||||
DSSDBG("no panel driver\n");
|
||||
r = -ENODEV;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
if (!try_module_get(dssdev->dev.driver->owner)) {
|
||||
r = -ENODEV;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
if (dssdev->ctrl.panel) {
|
||||
if (!try_module_get(dssdev->ctrl.panel->dev.driver->owner)) {
|
||||
r = -ENODEV;
|
||||
goto err1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
err1:
|
||||
module_put(dssdev->dev.driver->owner);
|
||||
err0:
|
||||
return r;
|
||||
}
|
||||
EXPORT_SYMBOL(omap_dss_start_device);
|
||||
|
||||
void omap_dss_stop_device(struct omap_dss_device *dssdev)
|
||||
{
|
||||
if (dssdev->ctrl.panel)
|
||||
module_put(dssdev->ctrl.panel->dev.driver->owner);
|
||||
|
||||
module_put(dssdev->dev.driver->owner);
|
||||
}
|
||||
EXPORT_SYMBOL(omap_dss_stop_device);
|
||||
|
399
drivers/video/omap2/dss/dpi.c
Normal file
399
drivers/video/omap2/dss/dpi.c
Normal file
@ -0,0 +1,399 @@
|
||||
/*
|
||||
* linux/drivers/video/omap2/dss/dpi.c
|
||||
*
|
||||
* Copyright (C) 2009 Nokia Corporation
|
||||
* Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
|
||||
*
|
||||
* Some code and ideas taken from drivers/video/omap/ driver
|
||||
* by Imre Deak.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define DSS_SUBSYS_NAME "DPI"
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/errno.h>
|
||||
|
||||
#include <plat/display.h>
|
||||
#include <plat/cpu.h>
|
||||
|
||||
#include "dss.h"
|
||||
|
||||
static struct {
|
||||
int update_enabled;
|
||||
} dpi;
|
||||
|
||||
#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
|
||||
static int dpi_set_dsi_clk(bool is_tft, unsigned long pck_req,
|
||||
unsigned long *fck, int *lck_div, int *pck_div)
|
||||
{
|
||||
struct dsi_clock_info dsi_cinfo;
|
||||
struct dispc_clock_info dispc_cinfo;
|
||||
int r;
|
||||
|
||||
r = dsi_pll_calc_clock_div_pck(is_tft, pck_req, &dsi_cinfo,
|
||||
&dispc_cinfo);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = dsi_pll_set_clock_div(&dsi_cinfo);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dss_select_clk_source(0, 1);
|
||||
|
||||
r = dispc_set_clock_div(&dispc_cinfo);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
*fck = dsi_cinfo.dsi1_pll_fclk;
|
||||
*lck_div = dispc_cinfo.lck_div;
|
||||
*pck_div = dispc_cinfo.pck_div;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int dpi_set_dispc_clk(bool is_tft, unsigned long pck_req,
|
||||
unsigned long *fck, int *lck_div, int *pck_div)
|
||||
{
|
||||
struct dss_clock_info dss_cinfo;
|
||||
struct dispc_clock_info dispc_cinfo;
|
||||
int r;
|
||||
|
||||
r = dss_calc_clock_div(is_tft, pck_req, &dss_cinfo, &dispc_cinfo);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = dss_set_clock_div(&dss_cinfo);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = dispc_set_clock_div(&dispc_cinfo);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
*fck = dss_cinfo.fck;
|
||||
*lck_div = dispc_cinfo.lck_div;
|
||||
*pck_div = dispc_cinfo.pck_div;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int dpi_set_mode(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_video_timings *t = &dssdev->panel.timings;
|
||||
int lck_div, pck_div;
|
||||
unsigned long fck;
|
||||
unsigned long pck;
|
||||
bool is_tft;
|
||||
int r = 0;
|
||||
|
||||
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
|
||||
|
||||
dispc_set_pol_freq(dssdev->panel.config, dssdev->panel.acbi,
|
||||
dssdev->panel.acb);
|
||||
|
||||
is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0;
|
||||
|
||||
#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
|
||||
r = dpi_set_dsi_clk(is_tft, t->pixel_clock * 1000,
|
||||
&fck, &lck_div, &pck_div);
|
||||
#else
|
||||
r = dpi_set_dispc_clk(is_tft, t->pixel_clock * 1000,
|
||||
&fck, &lck_div, &pck_div);
|
||||
#endif
|
||||
if (r)
|
||||
goto err0;
|
||||
|
||||
pck = fck / lck_div / pck_div / 1000;
|
||||
|
||||
if (pck != t->pixel_clock) {
|
||||
DSSWARN("Could not find exact pixel clock. "
|
||||
"Requested %d kHz, got %lu kHz\n",
|
||||
t->pixel_clock, pck);
|
||||
|
||||
t->pixel_clock = pck;
|
||||
}
|
||||
|
||||
dispc_set_lcd_timings(t);
|
||||
|
||||
err0:
|
||||
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int dpi_basic_init(struct omap_dss_device *dssdev)
|
||||
{
|
||||
bool is_tft;
|
||||
|
||||
is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0;
|
||||
|
||||
dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_BYPASS);
|
||||
dispc_set_lcd_display_type(is_tft ? OMAP_DSS_LCD_DISPLAY_TFT :
|
||||
OMAP_DSS_LCD_DISPLAY_STN);
|
||||
dispc_set_tft_data_lines(dssdev->phy.dpi.data_lines);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dpi_display_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = omap_dss_start_device(dssdev);
|
||||
if (r) {
|
||||
DSSERR("failed to start device\n");
|
||||
goto err0;
|
||||
}
|
||||
|
||||
if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
|
||||
DSSERR("display already enabled\n");
|
||||
r = -EINVAL;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
|
||||
|
||||
r = dpi_basic_init(dssdev);
|
||||
if (r)
|
||||
goto err2;
|
||||
|
||||
#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
|
||||
dss_clk_enable(DSS_CLK_FCK2);
|
||||
r = dsi_pll_init(dssdev, 0, 1);
|
||||
if (r)
|
||||
goto err3;
|
||||
#endif
|
||||
r = dpi_set_mode(dssdev);
|
||||
if (r)
|
||||
goto err4;
|
||||
|
||||
mdelay(2);
|
||||
|
||||
dispc_enable_lcd_out(1);
|
||||
|
||||
r = dssdev->driver->enable(dssdev);
|
||||
if (r)
|
||||
goto err5;
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
|
||||
|
||||
return 0;
|
||||
|
||||
err5:
|
||||
dispc_enable_lcd_out(0);
|
||||
err4:
|
||||
#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
|
||||
dsi_pll_uninit();
|
||||
err3:
|
||||
dss_clk_disable(DSS_CLK_FCK2);
|
||||
#endif
|
||||
err2:
|
||||
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
|
||||
err1:
|
||||
omap_dss_stop_device(dssdev);
|
||||
err0:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int dpi_display_resume(struct omap_dss_device *dssdev);
|
||||
|
||||
static void dpi_display_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED)
|
||||
return;
|
||||
|
||||
if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED)
|
||||
dpi_display_resume(dssdev);
|
||||
|
||||
dssdev->driver->disable(dssdev);
|
||||
|
||||
dispc_enable_lcd_out(0);
|
||||
|
||||
#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
|
||||
dss_select_clk_source(0, 0);
|
||||
dsi_pll_uninit();
|
||||
dss_clk_disable(DSS_CLK_FCK2);
|
||||
#endif
|
||||
|
||||
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
|
||||
|
||||
omap_dss_stop_device(dssdev);
|
||||
}
|
||||
|
||||
static int dpi_display_suspend(struct omap_dss_device *dssdev)
|
||||
{
|
||||
if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
|
||||
return -EINVAL;
|
||||
|
||||
DSSDBG("dpi_display_suspend\n");
|
||||
|
||||
if (dssdev->driver->suspend)
|
||||
dssdev->driver->suspend(dssdev);
|
||||
|
||||
dispc_enable_lcd_out(0);
|
||||
|
||||
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dpi_display_resume(struct omap_dss_device *dssdev)
|
||||
{
|
||||
if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED)
|
||||
return -EINVAL;
|
||||
|
||||
DSSDBG("dpi_display_resume\n");
|
||||
|
||||
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
|
||||
|
||||
dispc_enable_lcd_out(1);
|
||||
|
||||
if (dssdev->driver->resume)
|
||||
dssdev->driver->resume(dssdev);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dpi_set_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
DSSDBG("dpi_set_timings\n");
|
||||
dssdev->panel.timings = *timings;
|
||||
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
|
||||
dpi_set_mode(dssdev);
|
||||
dispc_go(OMAP_DSS_CHANNEL_LCD);
|
||||
}
|
||||
}
|
||||
|
||||
static int dpi_check_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
bool is_tft;
|
||||
int r;
|
||||
int lck_div, pck_div;
|
||||
unsigned long fck;
|
||||
unsigned long pck;
|
||||
|
||||
if (!dispc_lcd_timings_ok(timings))
|
||||
return -EINVAL;
|
||||
|
||||
if (timings->pixel_clock == 0)
|
||||
return -EINVAL;
|
||||
|
||||
is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0;
|
||||
|
||||
#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
|
||||
{
|
||||
struct dsi_clock_info dsi_cinfo;
|
||||
struct dispc_clock_info dispc_cinfo;
|
||||
r = dsi_pll_calc_clock_div_pck(is_tft,
|
||||
timings->pixel_clock * 1000,
|
||||
&dsi_cinfo, &dispc_cinfo);
|
||||
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
fck = dsi_cinfo.dsi1_pll_fclk;
|
||||
lck_div = dispc_cinfo.lck_div;
|
||||
pck_div = dispc_cinfo.pck_div;
|
||||
}
|
||||
#else
|
||||
{
|
||||
struct dss_clock_info dss_cinfo;
|
||||
struct dispc_clock_info dispc_cinfo;
|
||||
r = dss_calc_clock_div(is_tft, timings->pixel_clock * 1000,
|
||||
&dss_cinfo, &dispc_cinfo);
|
||||
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
fck = dss_cinfo.fck;
|
||||
lck_div = dispc_cinfo.lck_div;
|
||||
pck_div = dispc_cinfo.pck_div;
|
||||
}
|
||||
#endif
|
||||
|
||||
pck = fck / lck_div / pck_div / 1000;
|
||||
|
||||
timings->pixel_clock = pck;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dpi_get_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
*timings = dssdev->panel.timings;
|
||||
}
|
||||
|
||||
static int dpi_display_set_update_mode(struct omap_dss_device *dssdev,
|
||||
enum omap_dss_update_mode mode)
|
||||
{
|
||||
if (mode == OMAP_DSS_UPDATE_MANUAL)
|
||||
return -EINVAL;
|
||||
|
||||
if (mode == OMAP_DSS_UPDATE_DISABLED) {
|
||||
dispc_enable_lcd_out(0);
|
||||
dpi.update_enabled = 0;
|
||||
} else {
|
||||
dispc_enable_lcd_out(1);
|
||||
dpi.update_enabled = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum omap_dss_update_mode dpi_display_get_update_mode(
|
||||
struct omap_dss_device *dssdev)
|
||||
{
|
||||
return dpi.update_enabled ? OMAP_DSS_UPDATE_AUTO :
|
||||
OMAP_DSS_UPDATE_DISABLED;
|
||||
}
|
||||
|
||||
int dpi_init_display(struct omap_dss_device *dssdev)
|
||||
{
|
||||
DSSDBG("init_display\n");
|
||||
|
||||
dssdev->enable = dpi_display_enable;
|
||||
dssdev->disable = dpi_display_disable;
|
||||
dssdev->suspend = dpi_display_suspend;
|
||||
dssdev->resume = dpi_display_resume;
|
||||
dssdev->set_timings = dpi_set_timings;
|
||||
dssdev->check_timings = dpi_check_timings;
|
||||
dssdev->get_timings = dpi_get_timings;
|
||||
dssdev->set_update_mode = dpi_display_set_update_mode;
|
||||
dssdev->get_update_mode = dpi_display_get_update_mode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dpi_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dpi_exit(void)
|
||||
{
|
||||
}
|
||||
|
3710
drivers/video/omap2/dss/dsi.c
Normal file
3710
drivers/video/omap2/dss/dsi.c
Normal file
File diff suppressed because it is too large
Load Diff
596
drivers/video/omap2/dss/dss.c
Normal file
596
drivers/video/omap2/dss/dss.c
Normal file
@ -0,0 +1,596 @@
|
||||
/*
|
||||
* linux/drivers/video/omap2/dss/dss.c
|
||||
*
|
||||
* Copyright (C) 2009 Nokia Corporation
|
||||
* Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
|
||||
*
|
||||
* Some code and ideas taken from drivers/video/omap/ driver
|
||||
* by Imre Deak.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define DSS_SUBSYS_NAME "DSS"
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include <plat/display.h>
|
||||
#include "dss.h"
|
||||
|
||||
#define DSS_BASE 0x48050000
|
||||
|
||||
#define DSS_SZ_REGS SZ_512
|
||||
|
||||
struct dss_reg {
|
||||
u16 idx;
|
||||
};
|
||||
|
||||
#define DSS_REG(idx) ((const struct dss_reg) { idx })
|
||||
|
||||
#define DSS_REVISION DSS_REG(0x0000)
|
||||
#define DSS_SYSCONFIG DSS_REG(0x0010)
|
||||
#define DSS_SYSSTATUS DSS_REG(0x0014)
|
||||
#define DSS_IRQSTATUS DSS_REG(0x0018)
|
||||
#define DSS_CONTROL DSS_REG(0x0040)
|
||||
#define DSS_SDI_CONTROL DSS_REG(0x0044)
|
||||
#define DSS_PLL_CONTROL DSS_REG(0x0048)
|
||||
#define DSS_SDI_STATUS DSS_REG(0x005C)
|
||||
|
||||
#define REG_GET(idx, start, end) \
|
||||
FLD_GET(dss_read_reg(idx), start, end)
|
||||
|
||||
#define REG_FLD_MOD(idx, val, start, end) \
|
||||
dss_write_reg(idx, FLD_MOD(dss_read_reg(idx), val, start, end))
|
||||
|
||||
static struct {
|
||||
void __iomem *base;
|
||||
|
||||
struct clk *dpll4_m4_ck;
|
||||
|
||||
unsigned long cache_req_pck;
|
||||
unsigned long cache_prate;
|
||||
struct dss_clock_info cache_dss_cinfo;
|
||||
struct dispc_clock_info cache_dispc_cinfo;
|
||||
|
||||
u32 ctx[DSS_SZ_REGS / sizeof(u32)];
|
||||
} dss;
|
||||
|
||||
static int _omap_dss_wait_reset(void);
|
||||
|
||||
static inline void dss_write_reg(const struct dss_reg idx, u32 val)
|
||||
{
|
||||
__raw_writel(val, dss.base + idx.idx);
|
||||
}
|
||||
|
||||
static inline u32 dss_read_reg(const struct dss_reg idx)
|
||||
{
|
||||
return __raw_readl(dss.base + idx.idx);
|
||||
}
|
||||
|
||||
#define SR(reg) \
|
||||
dss.ctx[(DSS_##reg).idx / sizeof(u32)] = dss_read_reg(DSS_##reg)
|
||||
#define RR(reg) \
|
||||
dss_write_reg(DSS_##reg, dss.ctx[(DSS_##reg).idx / sizeof(u32)])
|
||||
|
||||
void dss_save_context(void)
|
||||
{
|
||||
if (cpu_is_omap24xx())
|
||||
return;
|
||||
|
||||
SR(SYSCONFIG);
|
||||
SR(CONTROL);
|
||||
|
||||
#ifdef CONFIG_OMAP2_DSS_SDI
|
||||
SR(SDI_CONTROL);
|
||||
SR(PLL_CONTROL);
|
||||
#endif
|
||||
}
|
||||
|
||||
void dss_restore_context(void)
|
||||
{
|
||||
if (_omap_dss_wait_reset())
|
||||
DSSERR("DSS not coming out of reset after sleep\n");
|
||||
|
||||
RR(SYSCONFIG);
|
||||
RR(CONTROL);
|
||||
|
||||
#ifdef CONFIG_OMAP2_DSS_SDI
|
||||
RR(SDI_CONTROL);
|
||||
RR(PLL_CONTROL);
|
||||
#endif
|
||||
}
|
||||
|
||||
#undef SR
|
||||
#undef RR
|
||||
|
||||
void dss_sdi_init(u8 datapairs)
|
||||
{
|
||||
u32 l;
|
||||
|
||||
BUG_ON(datapairs > 3 || datapairs < 1);
|
||||
|
||||
l = dss_read_reg(DSS_SDI_CONTROL);
|
||||
l = FLD_MOD(l, 0xf, 19, 15); /* SDI_PDIV */
|
||||
l = FLD_MOD(l, datapairs-1, 3, 2); /* SDI_PRSEL */
|
||||
l = FLD_MOD(l, 2, 1, 0); /* SDI_BWSEL */
|
||||
dss_write_reg(DSS_SDI_CONTROL, l);
|
||||
|
||||
l = dss_read_reg(DSS_PLL_CONTROL);
|
||||
l = FLD_MOD(l, 0x7, 25, 22); /* SDI_PLL_FREQSEL */
|
||||
l = FLD_MOD(l, 0xb, 16, 11); /* SDI_PLL_REGN */
|
||||
l = FLD_MOD(l, 0xb4, 10, 1); /* SDI_PLL_REGM */
|
||||
dss_write_reg(DSS_PLL_CONTROL, l);
|
||||
}
|
||||
|
||||
int dss_sdi_enable(void)
|
||||
{
|
||||
unsigned long timeout;
|
||||
|
||||
dispc_pck_free_enable(1);
|
||||
|
||||
/* Reset SDI PLL */
|
||||
REG_FLD_MOD(DSS_PLL_CONTROL, 1, 18, 18); /* SDI_PLL_SYSRESET */
|
||||
udelay(1); /* wait 2x PCLK */
|
||||
|
||||
/* Lock SDI PLL */
|
||||
REG_FLD_MOD(DSS_PLL_CONTROL, 1, 28, 28); /* SDI_PLL_GOBIT */
|
||||
|
||||
/* Waiting for PLL lock request to complete */
|
||||
timeout = jiffies + msecs_to_jiffies(500);
|
||||
while (dss_read_reg(DSS_SDI_STATUS) & (1 << 6)) {
|
||||
if (time_after_eq(jiffies, timeout)) {
|
||||
DSSERR("PLL lock request timed out\n");
|
||||
goto err1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Clearing PLL_GO bit */
|
||||
REG_FLD_MOD(DSS_PLL_CONTROL, 0, 28, 28);
|
||||
|
||||
/* Waiting for PLL to lock */
|
||||
timeout = jiffies + msecs_to_jiffies(500);
|
||||
while (!(dss_read_reg(DSS_SDI_STATUS) & (1 << 5))) {
|
||||
if (time_after_eq(jiffies, timeout)) {
|
||||
DSSERR("PLL lock timed out\n");
|
||||
goto err1;
|
||||
}
|
||||
}
|
||||
|
||||
dispc_lcd_enable_signal(1);
|
||||
|
||||
/* Waiting for SDI reset to complete */
|
||||
timeout = jiffies + msecs_to_jiffies(500);
|
||||
while (!(dss_read_reg(DSS_SDI_STATUS) & (1 << 2))) {
|
||||
if (time_after_eq(jiffies, timeout)) {
|
||||
DSSERR("SDI reset timed out\n");
|
||||
goto err2;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err2:
|
||||
dispc_lcd_enable_signal(0);
|
||||
err1:
|
||||
/* Reset SDI PLL */
|
||||
REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */
|
||||
|
||||
dispc_pck_free_enable(0);
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
void dss_sdi_disable(void)
|
||||
{
|
||||
dispc_lcd_enable_signal(0);
|
||||
|
||||
dispc_pck_free_enable(0);
|
||||
|
||||
/* Reset SDI PLL */
|
||||
REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */
|
||||
}
|
||||
|
||||
void dss_dump_clocks(struct seq_file *s)
|
||||
{
|
||||
unsigned long dpll4_ck_rate;
|
||||
unsigned long dpll4_m4_ck_rate;
|
||||
|
||||
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
|
||||
|
||||
dpll4_ck_rate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
|
||||
dpll4_m4_ck_rate = clk_get_rate(dss.dpll4_m4_ck);
|
||||
|
||||
seq_printf(s, "- DSS -\n");
|
||||
|
||||
seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate);
|
||||
|
||||
seq_printf(s, "dss1_alwon_fclk = %lu / %lu * 2 = %lu\n",
|
||||
dpll4_ck_rate,
|
||||
dpll4_ck_rate / dpll4_m4_ck_rate,
|
||||
dss_clk_get_rate(DSS_CLK_FCK1));
|
||||
|
||||
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
|
||||
}
|
||||
|
||||
void dss_dump_regs(struct seq_file *s)
|
||||
{
|
||||
#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dss_read_reg(r))
|
||||
|
||||
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
|
||||
|
||||
DUMPREG(DSS_REVISION);
|
||||
DUMPREG(DSS_SYSCONFIG);
|
||||
DUMPREG(DSS_SYSSTATUS);
|
||||
DUMPREG(DSS_IRQSTATUS);
|
||||
DUMPREG(DSS_CONTROL);
|
||||
DUMPREG(DSS_SDI_CONTROL);
|
||||
DUMPREG(DSS_PLL_CONTROL);
|
||||
DUMPREG(DSS_SDI_STATUS);
|
||||
|
||||
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
|
||||
#undef DUMPREG
|
||||
}
|
||||
|
||||
void dss_select_clk_source(bool dsi, bool dispc)
|
||||
{
|
||||
u32 r;
|
||||
r = dss_read_reg(DSS_CONTROL);
|
||||
r = FLD_MOD(r, dsi, 1, 1); /* DSI_CLK_SWITCH */
|
||||
r = FLD_MOD(r, dispc, 0, 0); /* DISPC_CLK_SWITCH */
|
||||
dss_write_reg(DSS_CONTROL, r);
|
||||
}
|
||||
|
||||
int dss_get_dsi_clk_source(void)
|
||||
{
|
||||
return FLD_GET(dss_read_reg(DSS_CONTROL), 1, 1);
|
||||
}
|
||||
|
||||
int dss_get_dispc_clk_source(void)
|
||||
{
|
||||
return FLD_GET(dss_read_reg(DSS_CONTROL), 0, 0);
|
||||
}
|
||||
|
||||
/* calculate clock rates using dividers in cinfo */
|
||||
int dss_calc_clock_rates(struct dss_clock_info *cinfo)
|
||||
{
|
||||
unsigned long prate;
|
||||
|
||||
if (cinfo->fck_div > 16 || cinfo->fck_div == 0)
|
||||
return -EINVAL;
|
||||
|
||||
prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
|
||||
|
||||
cinfo->fck = prate / cinfo->fck_div;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dss_set_clock_div(struct dss_clock_info *cinfo)
|
||||
{
|
||||
unsigned long prate;
|
||||
int r;
|
||||
|
||||
if (cpu_is_omap34xx()) {
|
||||
prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
|
||||
DSSDBG("dpll4_m4 = %ld\n", prate);
|
||||
|
||||
r = clk_set_rate(dss.dpll4_m4_ck, prate / cinfo->fck_div);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
DSSDBG("fck = %ld (%d)\n", cinfo->fck, cinfo->fck_div);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dss_get_clock_div(struct dss_clock_info *cinfo)
|
||||
{
|
||||
cinfo->fck = dss_clk_get_rate(DSS_CLK_FCK1);
|
||||
|
||||
if (cpu_is_omap34xx()) {
|
||||
unsigned long prate;
|
||||
prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
|
||||
cinfo->fck_div = prate / (cinfo->fck / 2);
|
||||
} else {
|
||||
cinfo->fck_div = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long dss_get_dpll4_rate(void)
|
||||
{
|
||||
if (cpu_is_omap34xx())
|
||||
return clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dss_calc_clock_div(bool is_tft, unsigned long req_pck,
|
||||
struct dss_clock_info *dss_cinfo,
|
||||
struct dispc_clock_info *dispc_cinfo)
|
||||
{
|
||||
unsigned long prate;
|
||||
struct dss_clock_info best_dss;
|
||||
struct dispc_clock_info best_dispc;
|
||||
|
||||
unsigned long fck;
|
||||
|
||||
u16 fck_div;
|
||||
|
||||
int match = 0;
|
||||
int min_fck_per_pck;
|
||||
|
||||
prate = dss_get_dpll4_rate();
|
||||
|
||||
fck = dss_clk_get_rate(DSS_CLK_FCK1);
|
||||
if (req_pck == dss.cache_req_pck &&
|
||||
((cpu_is_omap34xx() && prate == dss.cache_prate) ||
|
||||
dss.cache_dss_cinfo.fck == fck)) {
|
||||
DSSDBG("dispc clock info found from cache.\n");
|
||||
*dss_cinfo = dss.cache_dss_cinfo;
|
||||
*dispc_cinfo = dss.cache_dispc_cinfo;
|
||||
return 0;
|
||||
}
|
||||
|
||||
min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
|
||||
|
||||
if (min_fck_per_pck &&
|
||||
req_pck * min_fck_per_pck > DISPC_MAX_FCK) {
|
||||
DSSERR("Requested pixel clock not possible with the current "
|
||||
"OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning "
|
||||
"the constraint off.\n");
|
||||
min_fck_per_pck = 0;
|
||||
}
|
||||
|
||||
retry:
|
||||
memset(&best_dss, 0, sizeof(best_dss));
|
||||
memset(&best_dispc, 0, sizeof(best_dispc));
|
||||
|
||||
if (cpu_is_omap24xx()) {
|
||||
struct dispc_clock_info cur_dispc;
|
||||
/* XXX can we change the clock on omap2? */
|
||||
fck = dss_clk_get_rate(DSS_CLK_FCK1);
|
||||
fck_div = 1;
|
||||
|
||||
dispc_find_clk_divs(is_tft, req_pck, fck, &cur_dispc);
|
||||
match = 1;
|
||||
|
||||
best_dss.fck = fck;
|
||||
best_dss.fck_div = fck_div;
|
||||
|
||||
best_dispc = cur_dispc;
|
||||
|
||||
goto found;
|
||||
} else if (cpu_is_omap34xx()) {
|
||||
for (fck_div = 16; fck_div > 0; --fck_div) {
|
||||
struct dispc_clock_info cur_dispc;
|
||||
|
||||
fck = prate / fck_div * 2;
|
||||
|
||||
if (fck > DISPC_MAX_FCK)
|
||||
continue;
|
||||
|
||||
if (min_fck_per_pck &&
|
||||
fck < req_pck * min_fck_per_pck)
|
||||
continue;
|
||||
|
||||
match = 1;
|
||||
|
||||
dispc_find_clk_divs(is_tft, req_pck, fck, &cur_dispc);
|
||||
|
||||
if (abs(cur_dispc.pck - req_pck) <
|
||||
abs(best_dispc.pck - req_pck)) {
|
||||
|
||||
best_dss.fck = fck;
|
||||
best_dss.fck_div = fck_div;
|
||||
|
||||
best_dispc = cur_dispc;
|
||||
|
||||
if (cur_dispc.pck == req_pck)
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
BUG();
|
||||
}
|
||||
|
||||
found:
|
||||
if (!match) {
|
||||
if (min_fck_per_pck) {
|
||||
DSSERR("Could not find suitable clock settings.\n"
|
||||
"Turning FCK/PCK constraint off and"
|
||||
"trying again.\n");
|
||||
min_fck_per_pck = 0;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
DSSERR("Could not find suitable clock settings.\n");
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (dss_cinfo)
|
||||
*dss_cinfo = best_dss;
|
||||
if (dispc_cinfo)
|
||||
*dispc_cinfo = best_dispc;
|
||||
|
||||
dss.cache_req_pck = req_pck;
|
||||
dss.cache_prate = prate;
|
||||
dss.cache_dss_cinfo = best_dss;
|
||||
dss.cache_dispc_cinfo = best_dispc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static irqreturn_t dss_irq_handler_omap2(int irq, void *arg)
|
||||
{
|
||||
dispc_irq_handler();
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t dss_irq_handler_omap3(int irq, void *arg)
|
||||
{
|
||||
u32 irqstatus;
|
||||
|
||||
irqstatus = dss_read_reg(DSS_IRQSTATUS);
|
||||
|
||||
if (irqstatus & (1<<0)) /* DISPC_IRQ */
|
||||
dispc_irq_handler();
|
||||
#ifdef CONFIG_OMAP2_DSS_DSI
|
||||
if (irqstatus & (1<<1)) /* DSI_IRQ */
|
||||
dsi_irq_handler();
|
||||
#endif
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int _omap_dss_wait_reset(void)
|
||||
{
|
||||
unsigned timeout = 1000;
|
||||
|
||||
while (REG_GET(DSS_SYSSTATUS, 0, 0) == 0) {
|
||||
udelay(1);
|
||||
if (!--timeout) {
|
||||
DSSERR("soft reset failed\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _omap_dss_reset(void)
|
||||
{
|
||||
/* Soft reset */
|
||||
REG_FLD_MOD(DSS_SYSCONFIG, 1, 1, 1);
|
||||
return _omap_dss_wait_reset();
|
||||
}
|
||||
|
||||
void dss_set_venc_output(enum omap_dss_venc_type type)
|
||||
{
|
||||
int l = 0;
|
||||
|
||||
if (type == OMAP_DSS_VENC_TYPE_COMPOSITE)
|
||||
l = 0;
|
||||
else if (type == OMAP_DSS_VENC_TYPE_SVIDEO)
|
||||
l = 1;
|
||||
else
|
||||
BUG();
|
||||
|
||||
/* venc out selection. 0 = comp, 1 = svideo */
|
||||
REG_FLD_MOD(DSS_CONTROL, l, 6, 6);
|
||||
}
|
||||
|
||||
void dss_set_dac_pwrdn_bgz(bool enable)
|
||||
{
|
||||
REG_FLD_MOD(DSS_CONTROL, enable, 5, 5); /* DAC Power-Down Control */
|
||||
}
|
||||
|
||||
int dss_init(bool skip_init)
|
||||
{
|
||||
int r;
|
||||
u32 rev;
|
||||
|
||||
dss.base = ioremap(DSS_BASE, DSS_SZ_REGS);
|
||||
if (!dss.base) {
|
||||
DSSERR("can't ioremap DSS\n");
|
||||
r = -ENOMEM;
|
||||
goto fail0;
|
||||
}
|
||||
|
||||
if (!skip_init) {
|
||||
/* disable LCD and DIGIT output. This seems to fix the synclost
|
||||
* problem that we get, if the bootloader starts the DSS and
|
||||
* the kernel resets it */
|
||||
omap_writel(omap_readl(0x48050440) & ~0x3, 0x48050440);
|
||||
|
||||
/* We need to wait here a bit, otherwise we sometimes start to
|
||||
* get synclost errors, and after that only power cycle will
|
||||
* restore DSS functionality. I have no idea why this happens.
|
||||
* And we have to wait _before_ resetting the DSS, but after
|
||||
* enabling clocks.
|
||||
*/
|
||||
msleep(50);
|
||||
|
||||
_omap_dss_reset();
|
||||
}
|
||||
|
||||
/* autoidle */
|
||||
REG_FLD_MOD(DSS_SYSCONFIG, 1, 0, 0);
|
||||
|
||||
/* Select DPLL */
|
||||
REG_FLD_MOD(DSS_CONTROL, 0, 0, 0);
|
||||
|
||||
#ifdef CONFIG_OMAP2_DSS_VENC
|
||||
REG_FLD_MOD(DSS_CONTROL, 1, 4, 4); /* venc dac demen */
|
||||
REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */
|
||||
REG_FLD_MOD(DSS_CONTROL, 0, 2, 2); /* venc clock mode = normal */
|
||||
#endif
|
||||
|
||||
r = request_irq(INT_24XX_DSS_IRQ,
|
||||
cpu_is_omap24xx()
|
||||
? dss_irq_handler_omap2
|
||||
: dss_irq_handler_omap3,
|
||||
0, "OMAP DSS", NULL);
|
||||
|
||||
if (r < 0) {
|
||||
DSSERR("omap2 dss: request_irq failed\n");
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
if (cpu_is_omap34xx()) {
|
||||
dss.dpll4_m4_ck = clk_get(NULL, "dpll4_m4_ck");
|
||||
if (IS_ERR(dss.dpll4_m4_ck)) {
|
||||
DSSERR("Failed to get dpll4_m4_ck\n");
|
||||
r = PTR_ERR(dss.dpll4_m4_ck);
|
||||
goto fail2;
|
||||
}
|
||||
}
|
||||
|
||||
dss_save_context();
|
||||
|
||||
rev = dss_read_reg(DSS_REVISION);
|
||||
printk(KERN_INFO "OMAP DSS rev %d.%d\n",
|
||||
FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
|
||||
|
||||
return 0;
|
||||
|
||||
fail2:
|
||||
free_irq(INT_24XX_DSS_IRQ, NULL);
|
||||
fail1:
|
||||
iounmap(dss.base);
|
||||
fail0:
|
||||
return r;
|
||||
}
|
||||
|
||||
void dss_exit(void)
|
||||
{
|
||||
if (cpu_is_omap34xx())
|
||||
clk_put(dss.dpll4_m4_ck);
|
||||
|
||||
free_irq(INT_24XX_DSS_IRQ, NULL);
|
||||
|
||||
iounmap(dss.base);
|
||||
}
|
||||
|
370
drivers/video/omap2/dss/dss.h
Normal file
370
drivers/video/omap2/dss/dss.h
Normal file
@ -0,0 +1,370 @@
|
||||
/*
|
||||
* linux/drivers/video/omap2/dss/dss.h
|
||||
*
|
||||
* Copyright (C) 2009 Nokia Corporation
|
||||
* Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
|
||||
*
|
||||
* Some code and ideas taken from drivers/video/omap/ driver
|
||||
* by Imre Deak.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __OMAP2_DSS_H
|
||||
#define __OMAP2_DSS_H
|
||||
|
||||
#ifdef CONFIG_OMAP2_DSS_DEBUG_SUPPORT
|
||||
#define DEBUG
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
extern unsigned int dss_debug;
|
||||
#ifdef DSS_SUBSYS_NAME
|
||||
#define DSSDBG(format, ...) \
|
||||
if (dss_debug) \
|
||||
printk(KERN_DEBUG "omapdss " DSS_SUBSYS_NAME ": " format, \
|
||||
## __VA_ARGS__)
|
||||
#else
|
||||
#define DSSDBG(format, ...) \
|
||||
if (dss_debug) \
|
||||
printk(KERN_DEBUG "omapdss: " format, ## __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#ifdef DSS_SUBSYS_NAME
|
||||
#define DSSDBGF(format, ...) \
|
||||
if (dss_debug) \
|
||||
printk(KERN_DEBUG "omapdss " DSS_SUBSYS_NAME \
|
||||
": %s(" format ")\n", \
|
||||
__func__, \
|
||||
## __VA_ARGS__)
|
||||
#else
|
||||
#define DSSDBGF(format, ...) \
|
||||
if (dss_debug) \
|
||||
printk(KERN_DEBUG "omapdss: " \
|
||||
": %s(" format ")\n", \
|
||||
__func__, \
|
||||
## __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#else /* DEBUG */
|
||||
#define DSSDBG(format, ...)
|
||||
#define DSSDBGF(format, ...)
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef DSS_SUBSYS_NAME
|
||||
#define DSSERR(format, ...) \
|
||||
printk(KERN_ERR "omapdss " DSS_SUBSYS_NAME " error: " format, \
|
||||
## __VA_ARGS__)
|
||||
#else
|
||||
#define DSSERR(format, ...) \
|
||||
printk(KERN_ERR "omapdss error: " format, ## __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#ifdef DSS_SUBSYS_NAME
|
||||
#define DSSINFO(format, ...) \
|
||||
printk(KERN_INFO "omapdss " DSS_SUBSYS_NAME ": " format, \
|
||||
## __VA_ARGS__)
|
||||
#else
|
||||
#define DSSINFO(format, ...) \
|
||||
printk(KERN_INFO "omapdss: " format, ## __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#ifdef DSS_SUBSYS_NAME
|
||||
#define DSSWARN(format, ...) \
|
||||
printk(KERN_WARNING "omapdss " DSS_SUBSYS_NAME ": " format, \
|
||||
## __VA_ARGS__)
|
||||
#else
|
||||
#define DSSWARN(format, ...) \
|
||||
printk(KERN_WARNING "omapdss: " format, ## __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
/* OMAP TRM gives bitfields as start:end, where start is the higher bit
|
||||
number. For example 7:0 */
|
||||
#define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end))
|
||||
#define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end))
|
||||
#define FLD_GET(val, start, end) (((val) & FLD_MASK(start, end)) >> (end))
|
||||
#define FLD_MOD(orig, val, start, end) \
|
||||
(((orig) & ~FLD_MASK(start, end)) | FLD_VAL(val, start, end))
|
||||
|
||||
#define DISPC_MAX_FCK 173000000
|
||||
|
||||
enum omap_burst_size {
|
||||
OMAP_DSS_BURST_4x32 = 0,
|
||||
OMAP_DSS_BURST_8x32 = 1,
|
||||
OMAP_DSS_BURST_16x32 = 2,
|
||||
};
|
||||
|
||||
enum omap_parallel_interface_mode {
|
||||
OMAP_DSS_PARALLELMODE_BYPASS, /* MIPI DPI */
|
||||
OMAP_DSS_PARALLELMODE_RFBI, /* MIPI DBI */
|
||||
OMAP_DSS_PARALLELMODE_DSI,
|
||||
};
|
||||
|
||||
enum dss_clock {
|
||||
DSS_CLK_ICK = 1 << 0,
|
||||
DSS_CLK_FCK1 = 1 << 1,
|
||||
DSS_CLK_FCK2 = 1 << 2,
|
||||
DSS_CLK_54M = 1 << 3,
|
||||
DSS_CLK_96M = 1 << 4,
|
||||
};
|
||||
|
||||
struct dss_clock_info {
|
||||
/* rates that we get with dividers below */
|
||||
unsigned long fck;
|
||||
|
||||
/* dividers */
|
||||
u16 fck_div;
|
||||
};
|
||||
|
||||
struct dispc_clock_info {
|
||||
/* rates that we get with dividers below */
|
||||
unsigned long lck;
|
||||
unsigned long pck;
|
||||
|
||||
/* dividers */
|
||||
u16 lck_div;
|
||||
u16 pck_div;
|
||||
};
|
||||
|
||||
struct dsi_clock_info {
|
||||
/* rates that we get with dividers below */
|
||||
unsigned long fint;
|
||||
unsigned long clkin4ddr;
|
||||
unsigned long clkin;
|
||||
unsigned long dsi1_pll_fclk;
|
||||
unsigned long dsi2_pll_fclk;
|
||||
|
||||
unsigned long lp_clk;
|
||||
|
||||
/* dividers */
|
||||
u16 regn;
|
||||
u16 regm;
|
||||
u16 regm3;
|
||||
u16 regm4;
|
||||
|
||||
u16 lp_clk_div;
|
||||
|
||||
u8 highfreq;
|
||||
bool use_dss2_fck;
|
||||
};
|
||||
|
||||
struct seq_file;
|
||||
struct platform_device;
|
||||
|
||||
/* core */
|
||||
void dss_clk_enable(enum dss_clock clks);
|
||||
void dss_clk_disable(enum dss_clock clks);
|
||||
unsigned long dss_clk_get_rate(enum dss_clock clk);
|
||||
int dss_need_ctx_restore(void);
|
||||
void dss_dump_clocks(struct seq_file *s);
|
||||
struct bus_type *dss_get_bus(void);
|
||||
|
||||
/* display */
|
||||
int dss_suspend_all_devices(void);
|
||||
int dss_resume_all_devices(void);
|
||||
void dss_disable_all_devices(void);
|
||||
|
||||
void dss_init_device(struct platform_device *pdev,
|
||||
struct omap_dss_device *dssdev);
|
||||
void dss_uninit_device(struct platform_device *pdev,
|
||||
struct omap_dss_device *dssdev);
|
||||
bool dss_use_replication(struct omap_dss_device *dssdev,
|
||||
enum omap_color_mode mode);
|
||||
void default_get_overlay_fifo_thresholds(enum omap_plane plane,
|
||||
u32 fifo_size, enum omap_burst_size *burst_size,
|
||||
u32 *fifo_low, u32 *fifo_high);
|
||||
|
||||
/* manager */
|
||||
int dss_init_overlay_managers(struct platform_device *pdev);
|
||||
void dss_uninit_overlay_managers(struct platform_device *pdev);
|
||||
int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl);
|
||||
void dss_setup_partial_planes(struct omap_dss_device *dssdev,
|
||||
u16 *x, u16 *y, u16 *w, u16 *h);
|
||||
void dss_start_update(struct omap_dss_device *dssdev);
|
||||
|
||||
/* overlay */
|
||||
void dss_init_overlays(struct platform_device *pdev);
|
||||
void dss_uninit_overlays(struct platform_device *pdev);
|
||||
int dss_check_overlay(struct omap_overlay *ovl, struct omap_dss_device *dssdev);
|
||||
void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr);
|
||||
#ifdef L4_EXAMPLE
|
||||
void dss_overlay_setup_l4_manager(struct omap_overlay_manager *mgr);
|
||||
#endif
|
||||
void dss_recheck_connections(struct omap_dss_device *dssdev, bool force);
|
||||
|
||||
/* DSS */
|
||||
int dss_init(bool skip_init);
|
||||
void dss_exit(void);
|
||||
|
||||
void dss_save_context(void);
|
||||
void dss_restore_context(void);
|
||||
|
||||
void dss_dump_regs(struct seq_file *s);
|
||||
|
||||
void dss_sdi_init(u8 datapairs);
|
||||
int dss_sdi_enable(void);
|
||||
void dss_sdi_disable(void);
|
||||
|
||||
void dss_select_clk_source(bool dsi, bool dispc);
|
||||
int dss_get_dsi_clk_source(void);
|
||||
int dss_get_dispc_clk_source(void);
|
||||
void dss_set_venc_output(enum omap_dss_venc_type type);
|
||||
void dss_set_dac_pwrdn_bgz(bool enable);
|
||||
|
||||
unsigned long dss_get_dpll4_rate(void);
|
||||
int dss_calc_clock_rates(struct dss_clock_info *cinfo);
|
||||
int dss_set_clock_div(struct dss_clock_info *cinfo);
|
||||
int dss_get_clock_div(struct dss_clock_info *cinfo);
|
||||
int dss_calc_clock_div(bool is_tft, unsigned long req_pck,
|
||||
struct dss_clock_info *dss_cinfo,
|
||||
struct dispc_clock_info *dispc_cinfo);
|
||||
|
||||
/* SDI */
|
||||
int sdi_init(bool skip_init);
|
||||
void sdi_exit(void);
|
||||
int sdi_init_display(struct omap_dss_device *display);
|
||||
|
||||
/* DSI */
|
||||
int dsi_init(struct platform_device *pdev);
|
||||
void dsi_exit(void);
|
||||
|
||||
void dsi_dump_clocks(struct seq_file *s);
|
||||
void dsi_dump_regs(struct seq_file *s);
|
||||
|
||||
void dsi_save_context(void);
|
||||
void dsi_restore_context(void);
|
||||
|
||||
int dsi_init_display(struct omap_dss_device *display);
|
||||
void dsi_irq_handler(void);
|
||||
unsigned long dsi_get_dsi1_pll_rate(void);
|
||||
int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo);
|
||||
int dsi_pll_calc_clock_div_pck(bool is_tft, unsigned long req_pck,
|
||||
struct dsi_clock_info *cinfo,
|
||||
struct dispc_clock_info *dispc_cinfo);
|
||||
int dsi_pll_init(struct omap_dss_device *dssdev, bool enable_hsclk,
|
||||
bool enable_hsdiv);
|
||||
void dsi_pll_uninit(void);
|
||||
void dsi_get_overlay_fifo_thresholds(enum omap_plane plane,
|
||||
u32 fifo_size, enum omap_burst_size *burst_size,
|
||||
u32 *fifo_low, u32 *fifo_high);
|
||||
|
||||
/* DPI */
|
||||
int dpi_init(void);
|
||||
void dpi_exit(void);
|
||||
int dpi_init_display(struct omap_dss_device *dssdev);
|
||||
|
||||
/* DISPC */
|
||||
int dispc_init(void);
|
||||
void dispc_exit(void);
|
||||
void dispc_dump_clocks(struct seq_file *s);
|
||||
void dispc_dump_regs(struct seq_file *s);
|
||||
void dispc_irq_handler(void);
|
||||
void dispc_fake_vsync_irq(void);
|
||||
|
||||
void dispc_save_context(void);
|
||||
void dispc_restore_context(void);
|
||||
|
||||
void dispc_enable_sidle(void);
|
||||
void dispc_disable_sidle(void);
|
||||
|
||||
void dispc_lcd_enable_signal_polarity(bool act_high);
|
||||
void dispc_lcd_enable_signal(bool enable);
|
||||
void dispc_pck_free_enable(bool enable);
|
||||
void dispc_enable_fifohandcheck(bool enable);
|
||||
|
||||
void dispc_set_lcd_size(u16 width, u16 height);
|
||||
void dispc_set_digit_size(u16 width, u16 height);
|
||||
u32 dispc_get_plane_fifo_size(enum omap_plane plane);
|
||||
void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high);
|
||||
void dispc_enable_fifomerge(bool enable);
|
||||
void dispc_set_burst_size(enum omap_plane plane,
|
||||
enum omap_burst_size burst_size);
|
||||
|
||||
void dispc_set_plane_ba0(enum omap_plane plane, u32 paddr);
|
||||
void dispc_set_plane_ba1(enum omap_plane plane, u32 paddr);
|
||||
void dispc_set_plane_pos(enum omap_plane plane, u16 x, u16 y);
|
||||
void dispc_set_plane_size(enum omap_plane plane, u16 width, u16 height);
|
||||
void dispc_set_channel_out(enum omap_plane plane,
|
||||
enum omap_channel channel_out);
|
||||
|
||||
int dispc_setup_plane(enum omap_plane plane,
|
||||
u32 paddr, u16 screen_width,
|
||||
u16 pos_x, u16 pos_y,
|
||||
u16 width, u16 height,
|
||||
u16 out_width, u16 out_height,
|
||||
enum omap_color_mode color_mode,
|
||||
bool ilace,
|
||||
enum omap_dss_rotation_type rotation_type,
|
||||
u8 rotation, bool mirror,
|
||||
u8 global_alpha);
|
||||
|
||||
bool dispc_go_busy(enum omap_channel channel);
|
||||
void dispc_go(enum omap_channel channel);
|
||||
void dispc_enable_lcd_out(bool enable);
|
||||
void dispc_enable_digit_out(bool enable);
|
||||
int dispc_enable_plane(enum omap_plane plane, bool enable);
|
||||
void dispc_enable_replication(enum omap_plane plane, bool enable);
|
||||
|
||||
void dispc_set_parallel_interface_mode(enum omap_parallel_interface_mode mode);
|
||||
void dispc_set_tft_data_lines(u8 data_lines);
|
||||
void dispc_set_lcd_display_type(enum omap_lcd_display_type type);
|
||||
void dispc_set_loadmode(enum omap_dss_load_mode mode);
|
||||
|
||||
void dispc_set_default_color(enum omap_channel channel, u32 color);
|
||||
u32 dispc_get_default_color(enum omap_channel channel);
|
||||
void dispc_set_trans_key(enum omap_channel ch,
|
||||
enum omap_dss_trans_key_type type,
|
||||
u32 trans_key);
|
||||
void dispc_get_trans_key(enum omap_channel ch,
|
||||
enum omap_dss_trans_key_type *type,
|
||||
u32 *trans_key);
|
||||
void dispc_enable_trans_key(enum omap_channel ch, bool enable);
|
||||
void dispc_enable_alpha_blending(enum omap_channel ch, bool enable);
|
||||
bool dispc_trans_key_enabled(enum omap_channel ch);
|
||||
bool dispc_alpha_blending_enabled(enum omap_channel ch);
|
||||
|
||||
bool dispc_lcd_timings_ok(struct omap_video_timings *timings);
|
||||
void dispc_set_lcd_timings(struct omap_video_timings *timings);
|
||||
unsigned long dispc_fclk_rate(void);
|
||||
unsigned long dispc_lclk_rate(void);
|
||||
unsigned long dispc_pclk_rate(void);
|
||||
void dispc_set_pol_freq(enum omap_panel_config config, u8 acbi, u8 acb);
|
||||
void dispc_find_clk_divs(bool is_tft, unsigned long req_pck, unsigned long fck,
|
||||
struct dispc_clock_info *cinfo);
|
||||
int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
|
||||
struct dispc_clock_info *cinfo);
|
||||
int dispc_set_clock_div(struct dispc_clock_info *cinfo);
|
||||
int dispc_get_clock_div(struct dispc_clock_info *cinfo);
|
||||
|
||||
|
||||
/* VENC */
|
||||
int venc_init(struct platform_device *pdev);
|
||||
void venc_exit(void);
|
||||
void venc_dump_regs(struct seq_file *s);
|
||||
int venc_init_display(struct omap_dss_device *display);
|
||||
|
||||
/* RFBI */
|
||||
int rfbi_init(void);
|
||||
void rfbi_exit(void);
|
||||
void rfbi_dump_regs(struct seq_file *s);
|
||||
|
||||
int rfbi_configure(int rfbi_module, int bpp, int lines);
|
||||
void rfbi_enable_rfbi(bool enable);
|
||||
void rfbi_transfer_area(u16 width, u16 height,
|
||||
void (callback)(void *data), void *data);
|
||||
void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t);
|
||||
unsigned long rfbi_get_max_tx_rate(void);
|
||||
int rfbi_init_display(struct omap_dss_device *display);
|
||||
|
||||
#endif
|
1487
drivers/video/omap2/dss/manager.c
Normal file
1487
drivers/video/omap2/dss/manager.c
Normal file
File diff suppressed because it is too large
Load Diff
680
drivers/video/omap2/dss/overlay.c
Normal file
680
drivers/video/omap2/dss/overlay.c
Normal file
@ -0,0 +1,680 @@
|
||||
/*
|
||||
* linux/drivers/video/omap2/dss/overlay.c
|
||||
*
|
||||
* Copyright (C) 2009 Nokia Corporation
|
||||
* Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
|
||||
*
|
||||
* Some code and ideas taken from drivers/video/omap/ driver
|
||||
* by Imre Deak.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define DSS_SUBSYS_NAME "OVERLAY"
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include <plat/display.h>
|
||||
#include <plat/cpu.h>
|
||||
|
||||
#include "dss.h"
|
||||
|
||||
static int num_overlays;
|
||||
static struct list_head overlay_list;
|
||||
|
||||
static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n", ovl->name);
|
||||
}
|
||||
|
||||
static ssize_t overlay_manager_show(struct omap_overlay *ovl, char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n",
|
||||
ovl->manager ? ovl->manager->name : "<none>");
|
||||
}
|
||||
|
||||
static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf,
|
||||
size_t size)
|
||||
{
|
||||
int i, r;
|
||||
struct omap_overlay_manager *mgr = NULL;
|
||||
struct omap_overlay_manager *old_mgr;
|
||||
int len = size;
|
||||
|
||||
if (buf[size-1] == '\n')
|
||||
--len;
|
||||
|
||||
if (len > 0) {
|
||||
for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
|
||||
mgr = omap_dss_get_overlay_manager(i);
|
||||
|
||||
if (strncmp(buf, mgr->name, len) == 0)
|
||||
break;
|
||||
|
||||
mgr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (len > 0 && mgr == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
if (mgr)
|
||||
DSSDBG("manager %s found\n", mgr->name);
|
||||
|
||||
if (mgr == ovl->manager)
|
||||
return size;
|
||||
|
||||
old_mgr = ovl->manager;
|
||||
|
||||
/* detach old manager */
|
||||
if (old_mgr) {
|
||||
r = ovl->unset_manager(ovl);
|
||||
if (r) {
|
||||
DSSERR("detach failed\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
r = old_mgr->apply(old_mgr);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (mgr) {
|
||||
r = ovl->set_manager(ovl, mgr);
|
||||
if (r) {
|
||||
DSSERR("Failed to attach overlay\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
r = mgr->apply(mgr);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "%d,%d\n",
|
||||
ovl->info.width, ovl->info.height);
|
||||
}
|
||||
|
||||
static ssize_t overlay_screen_width_show(struct omap_overlay *ovl, char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", ovl->info.screen_width);
|
||||
}
|
||||
|
||||
static ssize_t overlay_position_show(struct omap_overlay *ovl, char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "%d,%d\n",
|
||||
ovl->info.pos_x, ovl->info.pos_y);
|
||||
}
|
||||
|
||||
static ssize_t overlay_position_store(struct omap_overlay *ovl,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
int r;
|
||||
char *last;
|
||||
struct omap_overlay_info info;
|
||||
|
||||
ovl->get_overlay_info(ovl, &info);
|
||||
|
||||
info.pos_x = simple_strtoul(buf, &last, 10);
|
||||
++last;
|
||||
if (last - buf >= size)
|
||||
return -EINVAL;
|
||||
|
||||
info.pos_y = simple_strtoul(last, &last, 10);
|
||||
|
||||
r = ovl->set_overlay_info(ovl, &info);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (ovl->manager) {
|
||||
r = ovl->manager->apply(ovl->manager);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t overlay_output_size_show(struct omap_overlay *ovl, char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "%d,%d\n",
|
||||
ovl->info.out_width, ovl->info.out_height);
|
||||
}
|
||||
|
||||
static ssize_t overlay_output_size_store(struct omap_overlay *ovl,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
int r;
|
||||
char *last;
|
||||
struct omap_overlay_info info;
|
||||
|
||||
ovl->get_overlay_info(ovl, &info);
|
||||
|
||||
info.out_width = simple_strtoul(buf, &last, 10);
|
||||
++last;
|
||||
if (last - buf >= size)
|
||||
return -EINVAL;
|
||||
|
||||
info.out_height = simple_strtoul(last, &last, 10);
|
||||
|
||||
r = ovl->set_overlay_info(ovl, &info);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (ovl->manager) {
|
||||
r = ovl->manager->apply(ovl->manager);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", ovl->info.enabled);
|
||||
}
|
||||
|
||||
static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf,
|
||||
size_t size)
|
||||
{
|
||||
int r;
|
||||
struct omap_overlay_info info;
|
||||
|
||||
ovl->get_overlay_info(ovl, &info);
|
||||
|
||||
info.enabled = simple_strtoul(buf, NULL, 10);
|
||||
|
||||
r = ovl->set_overlay_info(ovl, &info);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (ovl->manager) {
|
||||
r = ovl->manager->apply(ovl->manager);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t overlay_global_alpha_show(struct omap_overlay *ovl, char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n",
|
||||
ovl->info.global_alpha);
|
||||
}
|
||||
|
||||
static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
int r;
|
||||
struct omap_overlay_info info;
|
||||
|
||||
ovl->get_overlay_info(ovl, &info);
|
||||
|
||||
/* Video1 plane does not support global alpha
|
||||
* to always make it 255 completely opaque
|
||||
*/
|
||||
if (ovl->id == OMAP_DSS_VIDEO1)
|
||||
info.global_alpha = 255;
|
||||
else
|
||||
info.global_alpha = simple_strtoul(buf, NULL, 10);
|
||||
|
||||
r = ovl->set_overlay_info(ovl, &info);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (ovl->manager) {
|
||||
r = ovl->manager->apply(ovl->manager);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
struct overlay_attribute {
|
||||
struct attribute attr;
|
||||
ssize_t (*show)(struct omap_overlay *, char *);
|
||||
ssize_t (*store)(struct omap_overlay *, const char *, size_t);
|
||||
};
|
||||
|
||||
#define OVERLAY_ATTR(_name, _mode, _show, _store) \
|
||||
struct overlay_attribute overlay_attr_##_name = \
|
||||
__ATTR(_name, _mode, _show, _store)
|
||||
|
||||
static OVERLAY_ATTR(name, S_IRUGO, overlay_name_show, NULL);
|
||||
static OVERLAY_ATTR(manager, S_IRUGO|S_IWUSR,
|
||||
overlay_manager_show, overlay_manager_store);
|
||||
static OVERLAY_ATTR(input_size, S_IRUGO, overlay_input_size_show, NULL);
|
||||
static OVERLAY_ATTR(screen_width, S_IRUGO, overlay_screen_width_show, NULL);
|
||||
static OVERLAY_ATTR(position, S_IRUGO|S_IWUSR,
|
||||
overlay_position_show, overlay_position_store);
|
||||
static OVERLAY_ATTR(output_size, S_IRUGO|S_IWUSR,
|
||||
overlay_output_size_show, overlay_output_size_store);
|
||||
static OVERLAY_ATTR(enabled, S_IRUGO|S_IWUSR,
|
||||
overlay_enabled_show, overlay_enabled_store);
|
||||
static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR,
|
||||
overlay_global_alpha_show, overlay_global_alpha_store);
|
||||
|
||||
static struct attribute *overlay_sysfs_attrs[] = {
|
||||
&overlay_attr_name.attr,
|
||||
&overlay_attr_manager.attr,
|
||||
&overlay_attr_input_size.attr,
|
||||
&overlay_attr_screen_width.attr,
|
||||
&overlay_attr_position.attr,
|
||||
&overlay_attr_output_size.attr,
|
||||
&overlay_attr_enabled.attr,
|
||||
&overlay_attr_global_alpha.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static ssize_t overlay_attr_show(struct kobject *kobj, struct attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct omap_overlay *overlay;
|
||||
struct overlay_attribute *overlay_attr;
|
||||
|
||||
overlay = container_of(kobj, struct omap_overlay, kobj);
|
||||
overlay_attr = container_of(attr, struct overlay_attribute, attr);
|
||||
|
||||
if (!overlay_attr->show)
|
||||
return -ENOENT;
|
||||
|
||||
return overlay_attr->show(overlay, buf);
|
||||
}
|
||||
|
||||
static ssize_t overlay_attr_store(struct kobject *kobj, struct attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
struct omap_overlay *overlay;
|
||||
struct overlay_attribute *overlay_attr;
|
||||
|
||||
overlay = container_of(kobj, struct omap_overlay, kobj);
|
||||
overlay_attr = container_of(attr, struct overlay_attribute, attr);
|
||||
|
||||
if (!overlay_attr->store)
|
||||
return -ENOENT;
|
||||
|
||||
return overlay_attr->store(overlay, buf, size);
|
||||
}
|
||||
|
||||
static struct sysfs_ops overlay_sysfs_ops = {
|
||||
.show = overlay_attr_show,
|
||||
.store = overlay_attr_store,
|
||||
};
|
||||
|
||||
static struct kobj_type overlay_ktype = {
|
||||
.sysfs_ops = &overlay_sysfs_ops,
|
||||
.default_attrs = overlay_sysfs_attrs,
|
||||
};
|
||||
|
||||
/* Check if overlay parameters are compatible with display */
|
||||
int dss_check_overlay(struct omap_overlay *ovl, struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_overlay_info *info;
|
||||
u16 outw, outh;
|
||||
u16 dw, dh;
|
||||
|
||||
if (!dssdev)
|
||||
return 0;
|
||||
|
||||
if (!ovl->info.enabled)
|
||||
return 0;
|
||||
|
||||
info = &ovl->info;
|
||||
|
||||
if (info->paddr == 0) {
|
||||
DSSDBG("check_overlay failed: paddr 0\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dssdev->get_resolution(dssdev, &dw, &dh);
|
||||
|
||||
DSSDBG("check_overlay %d: (%d,%d %dx%d -> %dx%d) disp (%dx%d)\n",
|
||||
ovl->id,
|
||||
info->pos_x, info->pos_y,
|
||||
info->width, info->height,
|
||||
info->out_width, info->out_height,
|
||||
dw, dh);
|
||||
|
||||
if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
|
||||
outw = info->width;
|
||||
outh = info->height;
|
||||
} else {
|
||||
if (info->out_width == 0)
|
||||
outw = info->width;
|
||||
else
|
||||
outw = info->out_width;
|
||||
|
||||
if (info->out_height == 0)
|
||||
outh = info->height;
|
||||
else
|
||||
outh = info->out_height;
|
||||
}
|
||||
|
||||
if (dw < info->pos_x + outw) {
|
||||
DSSDBG("check_overlay failed 1: %d < %d + %d\n",
|
||||
dw, info->pos_x, outw);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (dh < info->pos_y + outh) {
|
||||
DSSDBG("check_overlay failed 2: %d < %d + %d\n",
|
||||
dh, info->pos_y, outh);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((ovl->supported_modes & info->color_mode) == 0) {
|
||||
DSSERR("overlay doesn't support mode %d\n", info->color_mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dss_ovl_set_overlay_info(struct omap_overlay *ovl,
|
||||
struct omap_overlay_info *info)
|
||||
{
|
||||
int r;
|
||||
struct omap_overlay_info old_info;
|
||||
|
||||
old_info = ovl->info;
|
||||
ovl->info = *info;
|
||||
|
||||
if (ovl->manager) {
|
||||
r = dss_check_overlay(ovl, ovl->manager->device);
|
||||
if (r) {
|
||||
ovl->info = old_info;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
ovl->info_dirty = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dss_ovl_get_overlay_info(struct omap_overlay *ovl,
|
||||
struct omap_overlay_info *info)
|
||||
{
|
||||
*info = ovl->info;
|
||||
}
|
||||
|
||||
static int dss_ovl_wait_for_go(struct omap_overlay *ovl)
|
||||
{
|
||||
return dss_mgr_wait_for_go_ovl(ovl);
|
||||
}
|
||||
|
||||
static int omap_dss_set_manager(struct omap_overlay *ovl,
|
||||
struct omap_overlay_manager *mgr)
|
||||
{
|
||||
if (!mgr)
|
||||
return -EINVAL;
|
||||
|
||||
if (ovl->manager) {
|
||||
DSSERR("overlay '%s' already has a manager '%s'\n",
|
||||
ovl->name, ovl->manager->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ovl->info.enabled) {
|
||||
DSSERR("overlay has to be disabled to change the manager\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ovl->manager = mgr;
|
||||
|
||||
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
|
||||
/* XXX: on manual update display, in auto update mode, a bug happens
|
||||
* here. When an overlay is first enabled on LCD, then it's disabled,
|
||||
* and the manager is changed to TV, we sometimes get SYNC_LOST_DIGIT
|
||||
* errors. Waiting before changing the channel_out fixes it. I'm
|
||||
* guessing that the overlay is still somehow being used for the LCD,
|
||||
* but I don't understand how or why. */
|
||||
msleep(40);
|
||||
dispc_set_channel_out(ovl->id, mgr->id);
|
||||
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int omap_dss_unset_manager(struct omap_overlay *ovl)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (!ovl->manager) {
|
||||
DSSERR("failed to detach overlay: manager not set\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ovl->info.enabled) {
|
||||
DSSERR("overlay has to be disabled to unset the manager\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = ovl->wait_for_go(ovl);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
ovl->manager = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int omap_dss_get_num_overlays(void)
|
||||
{
|
||||
return num_overlays;
|
||||
}
|
||||
EXPORT_SYMBOL(omap_dss_get_num_overlays);
|
||||
|
||||
struct omap_overlay *omap_dss_get_overlay(int num)
|
||||
{
|
||||
int i = 0;
|
||||
struct omap_overlay *ovl;
|
||||
|
||||
list_for_each_entry(ovl, &overlay_list, list) {
|
||||
if (i++ == num)
|
||||
return ovl;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(omap_dss_get_overlay);
|
||||
|
||||
static void omap_dss_add_overlay(struct omap_overlay *overlay)
|
||||
{
|
||||
++num_overlays;
|
||||
list_add_tail(&overlay->list, &overlay_list);
|
||||
}
|
||||
|
||||
static struct omap_overlay *dispc_overlays[3];
|
||||
|
||||
void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr)
|
||||
{
|
||||
mgr->num_overlays = 3;
|
||||
mgr->overlays = dispc_overlays;
|
||||
}
|
||||
|
||||
#ifdef L4_EXAMPLE
|
||||
static struct omap_overlay *l4_overlays[1];
|
||||
void dss_overlay_setup_l4_manager(struct omap_overlay_manager *mgr)
|
||||
{
|
||||
mgr->num_overlays = 1;
|
||||
mgr->overlays = l4_overlays;
|
||||
}
|
||||
#endif
|
||||
|
||||
void dss_init_overlays(struct platform_device *pdev)
|
||||
{
|
||||
int i, r;
|
||||
|
||||
INIT_LIST_HEAD(&overlay_list);
|
||||
|
||||
num_overlays = 0;
|
||||
|
||||
for (i = 0; i < 3; ++i) {
|
||||
struct omap_overlay *ovl;
|
||||
ovl = kzalloc(sizeof(*ovl), GFP_KERNEL);
|
||||
|
||||
BUG_ON(ovl == NULL);
|
||||
|
||||
switch (i) {
|
||||
case 0:
|
||||
ovl->name = "gfx";
|
||||
ovl->id = OMAP_DSS_GFX;
|
||||
ovl->supported_modes = cpu_is_omap34xx() ?
|
||||
OMAP_DSS_COLOR_GFX_OMAP3 :
|
||||
OMAP_DSS_COLOR_GFX_OMAP2;
|
||||
ovl->caps = OMAP_DSS_OVL_CAP_DISPC;
|
||||
ovl->info.global_alpha = 255;
|
||||
break;
|
||||
case 1:
|
||||
ovl->name = "vid1";
|
||||
ovl->id = OMAP_DSS_VIDEO1;
|
||||
ovl->supported_modes = cpu_is_omap34xx() ?
|
||||
OMAP_DSS_COLOR_VID1_OMAP3 :
|
||||
OMAP_DSS_COLOR_VID_OMAP2;
|
||||
ovl->caps = OMAP_DSS_OVL_CAP_SCALE |
|
||||
OMAP_DSS_OVL_CAP_DISPC;
|
||||
ovl->info.global_alpha = 255;
|
||||
break;
|
||||
case 2:
|
||||
ovl->name = "vid2";
|
||||
ovl->id = OMAP_DSS_VIDEO2;
|
||||
ovl->supported_modes = cpu_is_omap34xx() ?
|
||||
OMAP_DSS_COLOR_VID2_OMAP3 :
|
||||
OMAP_DSS_COLOR_VID_OMAP2;
|
||||
ovl->caps = OMAP_DSS_OVL_CAP_SCALE |
|
||||
OMAP_DSS_OVL_CAP_DISPC;
|
||||
ovl->info.global_alpha = 255;
|
||||
break;
|
||||
}
|
||||
|
||||
ovl->set_manager = &omap_dss_set_manager;
|
||||
ovl->unset_manager = &omap_dss_unset_manager;
|
||||
ovl->set_overlay_info = &dss_ovl_set_overlay_info;
|
||||
ovl->get_overlay_info = &dss_ovl_get_overlay_info;
|
||||
ovl->wait_for_go = &dss_ovl_wait_for_go;
|
||||
|
||||
omap_dss_add_overlay(ovl);
|
||||
|
||||
r = kobject_init_and_add(&ovl->kobj, &overlay_ktype,
|
||||
&pdev->dev.kobj, "overlay%d", i);
|
||||
|
||||
if (r) {
|
||||
DSSERR("failed to create sysfs file\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
dispc_overlays[i] = ovl;
|
||||
}
|
||||
|
||||
#ifdef L4_EXAMPLE
|
||||
{
|
||||
struct omap_overlay *ovl;
|
||||
ovl = kzalloc(sizeof(*ovl), GFP_KERNEL);
|
||||
|
||||
BUG_ON(ovl == NULL);
|
||||
|
||||
ovl->name = "l4";
|
||||
ovl->supported_modes = OMAP_DSS_COLOR_RGB24U;
|
||||
|
||||
ovl->set_manager = &omap_dss_set_manager;
|
||||
ovl->unset_manager = &omap_dss_unset_manager;
|
||||
ovl->set_overlay_info = &dss_ovl_set_overlay_info;
|
||||
ovl->get_overlay_info = &dss_ovl_get_overlay_info;
|
||||
|
||||
omap_dss_add_overlay(ovl);
|
||||
|
||||
r = kobject_init_and_add(&ovl->kobj, &overlay_ktype,
|
||||
&pdev->dev.kobj, "overlayl4");
|
||||
|
||||
if (r)
|
||||
DSSERR("failed to create sysfs file\n");
|
||||
|
||||
l4_overlays[0] = ovl;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* connect overlays to the new device, if not already connected. if force
|
||||
* selected, connect always. */
|
||||
void dss_recheck_connections(struct omap_dss_device *dssdev, bool force)
|
||||
{
|
||||
int i;
|
||||
struct omap_overlay_manager *lcd_mgr;
|
||||
struct omap_overlay_manager *tv_mgr;
|
||||
struct omap_overlay_manager *mgr = NULL;
|
||||
|
||||
lcd_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_LCD);
|
||||
tv_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_TV);
|
||||
|
||||
if (dssdev->type != OMAP_DISPLAY_TYPE_VENC) {
|
||||
if (!lcd_mgr->device || force) {
|
||||
if (lcd_mgr->device)
|
||||
lcd_mgr->unset_device(lcd_mgr);
|
||||
lcd_mgr->set_device(lcd_mgr, dssdev);
|
||||
mgr = lcd_mgr;
|
||||
}
|
||||
}
|
||||
|
||||
if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) {
|
||||
if (!tv_mgr->device || force) {
|
||||
if (tv_mgr->device)
|
||||
tv_mgr->unset_device(tv_mgr);
|
||||
tv_mgr->set_device(tv_mgr, dssdev);
|
||||
mgr = tv_mgr;
|
||||
}
|
||||
}
|
||||
|
||||
if (mgr) {
|
||||
for (i = 0; i < 3; i++) {
|
||||
struct omap_overlay *ovl;
|
||||
ovl = omap_dss_get_overlay(i);
|
||||
if (!ovl->manager || force) {
|
||||
if (ovl->manager)
|
||||
omap_dss_unset_manager(ovl);
|
||||
omap_dss_set_manager(ovl, mgr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dss_uninit_overlays(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_overlay *ovl;
|
||||
|
||||
while (!list_empty(&overlay_list)) {
|
||||
ovl = list_first_entry(&overlay_list,
|
||||
struct omap_overlay, list);
|
||||
list_del(&ovl->list);
|
||||
kobject_del(&ovl->kobj);
|
||||
kobject_put(&ovl->kobj);
|
||||
kfree(ovl);
|
||||
}
|
||||
|
||||
num_overlays = 0;
|
||||
}
|
||||
|
1309
drivers/video/omap2/dss/rfbi.c
Normal file
1309
drivers/video/omap2/dss/rfbi.c
Normal file
File diff suppressed because it is too large
Load Diff
277
drivers/video/omap2/dss/sdi.c
Normal file
277
drivers/video/omap2/dss/sdi.c
Normal file
@ -0,0 +1,277 @@
|
||||
/*
|
||||
* linux/drivers/video/omap2/dss/sdi.c
|
||||
*
|
||||
* Copyright (C) 2009 Nokia Corporation
|
||||
* Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define DSS_SUBSYS_NAME "SDI"
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include <plat/display.h>
|
||||
#include "dss.h"
|
||||
|
||||
static struct {
|
||||
bool skip_init;
|
||||
bool update_enabled;
|
||||
} sdi;
|
||||
|
||||
static void sdi_basic_init(void)
|
||||
{
|
||||
dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_BYPASS);
|
||||
|
||||
dispc_set_lcd_display_type(OMAP_DSS_LCD_DISPLAY_TFT);
|
||||
dispc_set_tft_data_lines(24);
|
||||
dispc_lcd_enable_signal_polarity(1);
|
||||
}
|
||||
|
||||
static int sdi_display_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_video_timings *t = &dssdev->panel.timings;
|
||||
struct dss_clock_info dss_cinfo;
|
||||
struct dispc_clock_info dispc_cinfo;
|
||||
u16 lck_div, pck_div;
|
||||
unsigned long fck;
|
||||
unsigned long pck;
|
||||
int r;
|
||||
|
||||
r = omap_dss_start_device(dssdev);
|
||||
if (r) {
|
||||
DSSERR("failed to start device\n");
|
||||
goto err0;
|
||||
}
|
||||
|
||||
if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
|
||||
DSSERR("dssdev already enabled\n");
|
||||
r = -EINVAL;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
/* In case of skip_init sdi_init has already enabled the clocks */
|
||||
if (!sdi.skip_init)
|
||||
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
|
||||
|
||||
sdi_basic_init();
|
||||
|
||||
/* 15.5.9.1.2 */
|
||||
dssdev->panel.config |= OMAP_DSS_LCD_RF | OMAP_DSS_LCD_ONOFF;
|
||||
|
||||
dispc_set_pol_freq(dssdev->panel.config, dssdev->panel.acbi,
|
||||
dssdev->panel.acb);
|
||||
|
||||
if (!sdi.skip_init) {
|
||||
r = dss_calc_clock_div(1, t->pixel_clock * 1000,
|
||||
&dss_cinfo, &dispc_cinfo);
|
||||
} else {
|
||||
r = dss_get_clock_div(&dss_cinfo);
|
||||
r = dispc_get_clock_div(&dispc_cinfo);
|
||||
}
|
||||
|
||||
if (r)
|
||||
goto err2;
|
||||
|
||||
fck = dss_cinfo.fck;
|
||||
lck_div = dispc_cinfo.lck_div;
|
||||
pck_div = dispc_cinfo.pck_div;
|
||||
|
||||
pck = fck / lck_div / pck_div / 1000;
|
||||
|
||||
if (pck != t->pixel_clock) {
|
||||
DSSWARN("Could not find exact pixel clock. Requested %d kHz, "
|
||||
"got %lu kHz\n",
|
||||
t->pixel_clock, pck);
|
||||
|
||||
t->pixel_clock = pck;
|
||||
}
|
||||
|
||||
|
||||
dispc_set_lcd_timings(t);
|
||||
|
||||
r = dss_set_clock_div(&dss_cinfo);
|
||||
if (r)
|
||||
goto err2;
|
||||
|
||||
r = dispc_set_clock_div(&dispc_cinfo);
|
||||
if (r)
|
||||
goto err2;
|
||||
|
||||
if (!sdi.skip_init) {
|
||||
dss_sdi_init(dssdev->phy.sdi.datapairs);
|
||||
r = dss_sdi_enable();
|
||||
if (r)
|
||||
goto err1;
|
||||
mdelay(2);
|
||||
}
|
||||
|
||||
dispc_enable_lcd_out(1);
|
||||
|
||||
if (dssdev->driver->enable) {
|
||||
r = dssdev->driver->enable(dssdev);
|
||||
if (r)
|
||||
goto err3;
|
||||
}
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
|
||||
|
||||
sdi.skip_init = 0;
|
||||
|
||||
return 0;
|
||||
err3:
|
||||
dispc_enable_lcd_out(0);
|
||||
err2:
|
||||
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
|
||||
err1:
|
||||
omap_dss_stop_device(dssdev);
|
||||
err0:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int sdi_display_resume(struct omap_dss_device *dssdev);
|
||||
|
||||
static void sdi_display_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED)
|
||||
return;
|
||||
|
||||
if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED)
|
||||
if (sdi_display_resume(dssdev))
|
||||
return;
|
||||
|
||||
if (dssdev->driver->disable)
|
||||
dssdev->driver->disable(dssdev);
|
||||
|
||||
dispc_enable_lcd_out(0);
|
||||
|
||||
dss_sdi_disable();
|
||||
|
||||
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
|
||||
|
||||
omap_dss_stop_device(dssdev);
|
||||
}
|
||||
|
||||
static int sdi_display_suspend(struct omap_dss_device *dssdev)
|
||||
{
|
||||
if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
|
||||
return -EINVAL;
|
||||
|
||||
if (dssdev->driver->suspend)
|
||||
dssdev->driver->suspend(dssdev);
|
||||
|
||||
dispc_enable_lcd_out(0);
|
||||
|
||||
dss_sdi_disable();
|
||||
|
||||
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sdi_display_resume(struct omap_dss_device *dssdev)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED)
|
||||
return -EINVAL;
|
||||
|
||||
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
|
||||
|
||||
r = dss_sdi_enable();
|
||||
if (r)
|
||||
goto err;
|
||||
mdelay(2);
|
||||
|
||||
dispc_enable_lcd_out(1);
|
||||
|
||||
if (dssdev->driver->resume)
|
||||
dssdev->driver->resume(dssdev);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
|
||||
|
||||
return 0;
|
||||
err:
|
||||
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int sdi_display_set_update_mode(struct omap_dss_device *dssdev,
|
||||
enum omap_dss_update_mode mode)
|
||||
{
|
||||
if (mode == OMAP_DSS_UPDATE_MANUAL)
|
||||
return -EINVAL;
|
||||
|
||||
if (mode == OMAP_DSS_UPDATE_DISABLED) {
|
||||
dispc_enable_lcd_out(0);
|
||||
sdi.update_enabled = 0;
|
||||
} else {
|
||||
dispc_enable_lcd_out(1);
|
||||
sdi.update_enabled = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum omap_dss_update_mode sdi_display_get_update_mode(
|
||||
struct omap_dss_device *dssdev)
|
||||
{
|
||||
return sdi.update_enabled ? OMAP_DSS_UPDATE_AUTO :
|
||||
OMAP_DSS_UPDATE_DISABLED;
|
||||
}
|
||||
|
||||
static void sdi_get_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
*timings = dssdev->panel.timings;
|
||||
}
|
||||
|
||||
int sdi_init_display(struct omap_dss_device *dssdev)
|
||||
{
|
||||
DSSDBG("SDI init\n");
|
||||
|
||||
dssdev->enable = sdi_display_enable;
|
||||
dssdev->disable = sdi_display_disable;
|
||||
dssdev->suspend = sdi_display_suspend;
|
||||
dssdev->resume = sdi_display_resume;
|
||||
dssdev->set_update_mode = sdi_display_set_update_mode;
|
||||
dssdev->get_update_mode = sdi_display_get_update_mode;
|
||||
dssdev->get_timings = sdi_get_timings;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sdi_init(bool skip_init)
|
||||
{
|
||||
/* we store this for first display enable, then clear it */
|
||||
sdi.skip_init = skip_init;
|
||||
|
||||
/*
|
||||
* Enable clocks already here, otherwise there would be a toggle
|
||||
* of them until sdi_display_enable is called.
|
||||
*/
|
||||
if (skip_init)
|
||||
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sdi_exit(void)
|
||||
{
|
||||
}
|
797
drivers/video/omap2/dss/venc.c
Normal file
797
drivers/video/omap2/dss/venc.c
Normal file
@ -0,0 +1,797 @@
|
||||
/*
|
||||
* linux/drivers/video/omap2/dss/venc.c
|
||||
*
|
||||
* Copyright (C) 2009 Nokia Corporation
|
||||
* Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
|
||||
*
|
||||
* VENC settings from TI's DSS driver
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define DSS_SUBSYS_NAME "VENC"
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include <plat/display.h>
|
||||
#include <plat/cpu.h>
|
||||
|
||||
#include "dss.h"
|
||||
|
||||
#define VENC_BASE 0x48050C00
|
||||
|
||||
/* Venc registers */
|
||||
#define VENC_REV_ID 0x00
|
||||
#define VENC_STATUS 0x04
|
||||
#define VENC_F_CONTROL 0x08
|
||||
#define VENC_VIDOUT_CTRL 0x10
|
||||
#define VENC_SYNC_CTRL 0x14
|
||||
#define VENC_LLEN 0x1C
|
||||
#define VENC_FLENS 0x20
|
||||
#define VENC_HFLTR_CTRL 0x24
|
||||
#define VENC_CC_CARR_WSS_CARR 0x28
|
||||
#define VENC_C_PHASE 0x2C
|
||||
#define VENC_GAIN_U 0x30
|
||||
#define VENC_GAIN_V 0x34
|
||||
#define VENC_GAIN_Y 0x38
|
||||
#define VENC_BLACK_LEVEL 0x3C
|
||||
#define VENC_BLANK_LEVEL 0x40
|
||||
#define VENC_X_COLOR 0x44
|
||||
#define VENC_M_CONTROL 0x48
|
||||
#define VENC_BSTAMP_WSS_DATA 0x4C
|
||||
#define VENC_S_CARR 0x50
|
||||
#define VENC_LINE21 0x54
|
||||
#define VENC_LN_SEL 0x58
|
||||
#define VENC_L21__WC_CTL 0x5C
|
||||
#define VENC_HTRIGGER_VTRIGGER 0x60
|
||||
#define VENC_SAVID__EAVID 0x64
|
||||
#define VENC_FLEN__FAL 0x68
|
||||
#define VENC_LAL__PHASE_RESET 0x6C
|
||||
#define VENC_HS_INT_START_STOP_X 0x70
|
||||
#define VENC_HS_EXT_START_STOP_X 0x74
|
||||
#define VENC_VS_INT_START_X 0x78
|
||||
#define VENC_VS_INT_STOP_X__VS_INT_START_Y 0x7C
|
||||
#define VENC_VS_INT_STOP_Y__VS_EXT_START_X 0x80
|
||||
#define VENC_VS_EXT_STOP_X__VS_EXT_START_Y 0x84
|
||||
#define VENC_VS_EXT_STOP_Y 0x88
|
||||
#define VENC_AVID_START_STOP_X 0x90
|
||||
#define VENC_AVID_START_STOP_Y 0x94
|
||||
#define VENC_FID_INT_START_X__FID_INT_START_Y 0xA0
|
||||
#define VENC_FID_INT_OFFSET_Y__FID_EXT_START_X 0xA4
|
||||
#define VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y 0xA8
|
||||
#define VENC_TVDETGP_INT_START_STOP_X 0xB0
|
||||
#define VENC_TVDETGP_INT_START_STOP_Y 0xB4
|
||||
#define VENC_GEN_CTRL 0xB8
|
||||
#define VENC_OUTPUT_CONTROL 0xC4
|
||||
#define VENC_OUTPUT_TEST 0xC8
|
||||
#define VENC_DAC_B__DAC_C 0xC8
|
||||
|
||||
struct venc_config {
|
||||
u32 f_control;
|
||||
u32 vidout_ctrl;
|
||||
u32 sync_ctrl;
|
||||
u32 llen;
|
||||
u32 flens;
|
||||
u32 hfltr_ctrl;
|
||||
u32 cc_carr_wss_carr;
|
||||
u32 c_phase;
|
||||
u32 gain_u;
|
||||
u32 gain_v;
|
||||
u32 gain_y;
|
||||
u32 black_level;
|
||||
u32 blank_level;
|
||||
u32 x_color;
|
||||
u32 m_control;
|
||||
u32 bstamp_wss_data;
|
||||
u32 s_carr;
|
||||
u32 line21;
|
||||
u32 ln_sel;
|
||||
u32 l21__wc_ctl;
|
||||
u32 htrigger_vtrigger;
|
||||
u32 savid__eavid;
|
||||
u32 flen__fal;
|
||||
u32 lal__phase_reset;
|
||||
u32 hs_int_start_stop_x;
|
||||
u32 hs_ext_start_stop_x;
|
||||
u32 vs_int_start_x;
|
||||
u32 vs_int_stop_x__vs_int_start_y;
|
||||
u32 vs_int_stop_y__vs_ext_start_x;
|
||||
u32 vs_ext_stop_x__vs_ext_start_y;
|
||||
u32 vs_ext_stop_y;
|
||||
u32 avid_start_stop_x;
|
||||
u32 avid_start_stop_y;
|
||||
u32 fid_int_start_x__fid_int_start_y;
|
||||
u32 fid_int_offset_y__fid_ext_start_x;
|
||||
u32 fid_ext_start_y__fid_ext_offset_y;
|
||||
u32 tvdetgp_int_start_stop_x;
|
||||
u32 tvdetgp_int_start_stop_y;
|
||||
u32 gen_ctrl;
|
||||
};
|
||||
|
||||
/* from TRM */
|
||||
static const struct venc_config venc_config_pal_trm = {
|
||||
.f_control = 0,
|
||||
.vidout_ctrl = 1,
|
||||
.sync_ctrl = 0x40,
|
||||
.llen = 0x35F, /* 863 */
|
||||
.flens = 0x270, /* 624 */
|
||||
.hfltr_ctrl = 0,
|
||||
.cc_carr_wss_carr = 0x2F7225ED,
|
||||
.c_phase = 0,
|
||||
.gain_u = 0x111,
|
||||
.gain_v = 0x181,
|
||||
.gain_y = 0x140,
|
||||
.black_level = 0x3B,
|
||||
.blank_level = 0x3B,
|
||||
.x_color = 0x7,
|
||||
.m_control = 0x2,
|
||||
.bstamp_wss_data = 0x3F,
|
||||
.s_carr = 0x2A098ACB,
|
||||
.line21 = 0,
|
||||
.ln_sel = 0x01290015,
|
||||
.l21__wc_ctl = 0x0000F603,
|
||||
.htrigger_vtrigger = 0,
|
||||
|
||||
.savid__eavid = 0x06A70108,
|
||||
.flen__fal = 0x00180270,
|
||||
.lal__phase_reset = 0x00040135,
|
||||
.hs_int_start_stop_x = 0x00880358,
|
||||
.hs_ext_start_stop_x = 0x000F035F,
|
||||
.vs_int_start_x = 0x01A70000,
|
||||
.vs_int_stop_x__vs_int_start_y = 0x000001A7,
|
||||
.vs_int_stop_y__vs_ext_start_x = 0x01AF0000,
|
||||
.vs_ext_stop_x__vs_ext_start_y = 0x000101AF,
|
||||
.vs_ext_stop_y = 0x00000025,
|
||||
.avid_start_stop_x = 0x03530083,
|
||||
.avid_start_stop_y = 0x026C002E,
|
||||
.fid_int_start_x__fid_int_start_y = 0x0001008A,
|
||||
.fid_int_offset_y__fid_ext_start_x = 0x002E0138,
|
||||
.fid_ext_start_y__fid_ext_offset_y = 0x01380001,
|
||||
|
||||
.tvdetgp_int_start_stop_x = 0x00140001,
|
||||
.tvdetgp_int_start_stop_y = 0x00010001,
|
||||
.gen_ctrl = 0x00FF0000,
|
||||
};
|
||||
|
||||
/* from TRM */
|
||||
static const struct venc_config venc_config_ntsc_trm = {
|
||||
.f_control = 0,
|
||||
.vidout_ctrl = 1,
|
||||
.sync_ctrl = 0x8040,
|
||||
.llen = 0x359,
|
||||
.flens = 0x20C,
|
||||
.hfltr_ctrl = 0,
|
||||
.cc_carr_wss_carr = 0x043F2631,
|
||||
.c_phase = 0,
|
||||
.gain_u = 0x102,
|
||||
.gain_v = 0x16C,
|
||||
.gain_y = 0x12F,
|
||||
.black_level = 0x43,
|
||||
.blank_level = 0x38,
|
||||
.x_color = 0x7,
|
||||
.m_control = 0x1,
|
||||
.bstamp_wss_data = 0x38,
|
||||
.s_carr = 0x21F07C1F,
|
||||
.line21 = 0,
|
||||
.ln_sel = 0x01310011,
|
||||
.l21__wc_ctl = 0x0000F003,
|
||||
.htrigger_vtrigger = 0,
|
||||
|
||||
.savid__eavid = 0x069300F4,
|
||||
.flen__fal = 0x0016020C,
|
||||
.lal__phase_reset = 0x00060107,
|
||||
.hs_int_start_stop_x = 0x008E0350,
|
||||
.hs_ext_start_stop_x = 0x000F0359,
|
||||
.vs_int_start_x = 0x01A00000,
|
||||
.vs_int_stop_x__vs_int_start_y = 0x020701A0,
|
||||
.vs_int_stop_y__vs_ext_start_x = 0x01AC0024,
|
||||
.vs_ext_stop_x__vs_ext_start_y = 0x020D01AC,
|
||||
.vs_ext_stop_y = 0x00000006,
|
||||
.avid_start_stop_x = 0x03480078,
|
||||
.avid_start_stop_y = 0x02060024,
|
||||
.fid_int_start_x__fid_int_start_y = 0x0001008A,
|
||||
.fid_int_offset_y__fid_ext_start_x = 0x01AC0106,
|
||||
.fid_ext_start_y__fid_ext_offset_y = 0x01060006,
|
||||
|
||||
.tvdetgp_int_start_stop_x = 0x00140001,
|
||||
.tvdetgp_int_start_stop_y = 0x00010001,
|
||||
.gen_ctrl = 0x00F90000,
|
||||
};
|
||||
|
||||
static const struct venc_config venc_config_pal_bdghi = {
|
||||
.f_control = 0,
|
||||
.vidout_ctrl = 0,
|
||||
.sync_ctrl = 0,
|
||||
.hfltr_ctrl = 0,
|
||||
.x_color = 0,
|
||||
.line21 = 0,
|
||||
.ln_sel = 21,
|
||||
.htrigger_vtrigger = 0,
|
||||
.tvdetgp_int_start_stop_x = 0x00140001,
|
||||
.tvdetgp_int_start_stop_y = 0x00010001,
|
||||
.gen_ctrl = 0x00FB0000,
|
||||
|
||||
.llen = 864-1,
|
||||
.flens = 625-1,
|
||||
.cc_carr_wss_carr = 0x2F7625ED,
|
||||
.c_phase = 0xDF,
|
||||
.gain_u = 0x111,
|
||||
.gain_v = 0x181,
|
||||
.gain_y = 0x140,
|
||||
.black_level = 0x3e,
|
||||
.blank_level = 0x3e,
|
||||
.m_control = 0<<2 | 1<<1,
|
||||
.bstamp_wss_data = 0x42,
|
||||
.s_carr = 0x2a098acb,
|
||||
.l21__wc_ctl = 0<<13 | 0x16<<8 | 0<<0,
|
||||
.savid__eavid = 0x06A70108,
|
||||
.flen__fal = 23<<16 | 624<<0,
|
||||
.lal__phase_reset = 2<<17 | 310<<0,
|
||||
.hs_int_start_stop_x = 0x00920358,
|
||||
.hs_ext_start_stop_x = 0x000F035F,
|
||||
.vs_int_start_x = 0x1a7<<16,
|
||||
.vs_int_stop_x__vs_int_start_y = 0x000601A7,
|
||||
.vs_int_stop_y__vs_ext_start_x = 0x01AF0036,
|
||||
.vs_ext_stop_x__vs_ext_start_y = 0x27101af,
|
||||
.vs_ext_stop_y = 0x05,
|
||||
.avid_start_stop_x = 0x03530082,
|
||||
.avid_start_stop_y = 0x0270002E,
|
||||
.fid_int_start_x__fid_int_start_y = 0x0005008A,
|
||||
.fid_int_offset_y__fid_ext_start_x = 0x002E0138,
|
||||
.fid_ext_start_y__fid_ext_offset_y = 0x01380005,
|
||||
};
|
||||
|
||||
const struct omap_video_timings omap_dss_pal_timings = {
|
||||
.x_res = 720,
|
||||
.y_res = 574,
|
||||
.pixel_clock = 13500,
|
||||
.hsw = 64,
|
||||
.hfp = 12,
|
||||
.hbp = 68,
|
||||
.vsw = 5,
|
||||
.vfp = 5,
|
||||
.vbp = 41,
|
||||
};
|
||||
EXPORT_SYMBOL(omap_dss_pal_timings);
|
||||
|
||||
const struct omap_video_timings omap_dss_ntsc_timings = {
|
||||
.x_res = 720,
|
||||
.y_res = 482,
|
||||
.pixel_clock = 13500,
|
||||
.hsw = 64,
|
||||
.hfp = 16,
|
||||
.hbp = 58,
|
||||
.vsw = 6,
|
||||
.vfp = 6,
|
||||
.vbp = 31,
|
||||
};
|
||||
EXPORT_SYMBOL(omap_dss_ntsc_timings);
|
||||
|
||||
static struct {
|
||||
void __iomem *base;
|
||||
struct mutex venc_lock;
|
||||
u32 wss_data;
|
||||
struct regulator *vdda_dac_reg;
|
||||
} venc;
|
||||
|
||||
static inline void venc_write_reg(int idx, u32 val)
|
||||
{
|
||||
__raw_writel(val, venc.base + idx);
|
||||
}
|
||||
|
||||
static inline u32 venc_read_reg(int idx)
|
||||
{
|
||||
u32 l = __raw_readl(venc.base + idx);
|
||||
return l;
|
||||
}
|
||||
|
||||
static void venc_write_config(const struct venc_config *config)
|
||||
{
|
||||
DSSDBG("write venc conf\n");
|
||||
|
||||
venc_write_reg(VENC_LLEN, config->llen);
|
||||
venc_write_reg(VENC_FLENS, config->flens);
|
||||
venc_write_reg(VENC_CC_CARR_WSS_CARR, config->cc_carr_wss_carr);
|
||||
venc_write_reg(VENC_C_PHASE, config->c_phase);
|
||||
venc_write_reg(VENC_GAIN_U, config->gain_u);
|
||||
venc_write_reg(VENC_GAIN_V, config->gain_v);
|
||||
venc_write_reg(VENC_GAIN_Y, config->gain_y);
|
||||
venc_write_reg(VENC_BLACK_LEVEL, config->black_level);
|
||||
venc_write_reg(VENC_BLANK_LEVEL, config->blank_level);
|
||||
venc_write_reg(VENC_M_CONTROL, config->m_control);
|
||||
venc_write_reg(VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data |
|
||||
venc.wss_data);
|
||||
venc_write_reg(VENC_S_CARR, config->s_carr);
|
||||
venc_write_reg(VENC_L21__WC_CTL, config->l21__wc_ctl);
|
||||
venc_write_reg(VENC_SAVID__EAVID, config->savid__eavid);
|
||||
venc_write_reg(VENC_FLEN__FAL, config->flen__fal);
|
||||
venc_write_reg(VENC_LAL__PHASE_RESET, config->lal__phase_reset);
|
||||
venc_write_reg(VENC_HS_INT_START_STOP_X, config->hs_int_start_stop_x);
|
||||
venc_write_reg(VENC_HS_EXT_START_STOP_X, config->hs_ext_start_stop_x);
|
||||
venc_write_reg(VENC_VS_INT_START_X, config->vs_int_start_x);
|
||||
venc_write_reg(VENC_VS_INT_STOP_X__VS_INT_START_Y,
|
||||
config->vs_int_stop_x__vs_int_start_y);
|
||||
venc_write_reg(VENC_VS_INT_STOP_Y__VS_EXT_START_X,
|
||||
config->vs_int_stop_y__vs_ext_start_x);
|
||||
venc_write_reg(VENC_VS_EXT_STOP_X__VS_EXT_START_Y,
|
||||
config->vs_ext_stop_x__vs_ext_start_y);
|
||||
venc_write_reg(VENC_VS_EXT_STOP_Y, config->vs_ext_stop_y);
|
||||
venc_write_reg(VENC_AVID_START_STOP_X, config->avid_start_stop_x);
|
||||
venc_write_reg(VENC_AVID_START_STOP_Y, config->avid_start_stop_y);
|
||||
venc_write_reg(VENC_FID_INT_START_X__FID_INT_START_Y,
|
||||
config->fid_int_start_x__fid_int_start_y);
|
||||
venc_write_reg(VENC_FID_INT_OFFSET_Y__FID_EXT_START_X,
|
||||
config->fid_int_offset_y__fid_ext_start_x);
|
||||
venc_write_reg(VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y,
|
||||
config->fid_ext_start_y__fid_ext_offset_y);
|
||||
|
||||
venc_write_reg(VENC_DAC_B__DAC_C, venc_read_reg(VENC_DAC_B__DAC_C));
|
||||
venc_write_reg(VENC_VIDOUT_CTRL, config->vidout_ctrl);
|
||||
venc_write_reg(VENC_HFLTR_CTRL, config->hfltr_ctrl);
|
||||
venc_write_reg(VENC_X_COLOR, config->x_color);
|
||||
venc_write_reg(VENC_LINE21, config->line21);
|
||||
venc_write_reg(VENC_LN_SEL, config->ln_sel);
|
||||
venc_write_reg(VENC_HTRIGGER_VTRIGGER, config->htrigger_vtrigger);
|
||||
venc_write_reg(VENC_TVDETGP_INT_START_STOP_X,
|
||||
config->tvdetgp_int_start_stop_x);
|
||||
venc_write_reg(VENC_TVDETGP_INT_START_STOP_Y,
|
||||
config->tvdetgp_int_start_stop_y);
|
||||
venc_write_reg(VENC_GEN_CTRL, config->gen_ctrl);
|
||||
venc_write_reg(VENC_F_CONTROL, config->f_control);
|
||||
venc_write_reg(VENC_SYNC_CTRL, config->sync_ctrl);
|
||||
}
|
||||
|
||||
static void venc_reset(void)
|
||||
{
|
||||
int t = 1000;
|
||||
|
||||
venc_write_reg(VENC_F_CONTROL, 1<<8);
|
||||
while (venc_read_reg(VENC_F_CONTROL) & (1<<8)) {
|
||||
if (--t == 0) {
|
||||
DSSERR("Failed to reset venc\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* the magical sleep that makes things work */
|
||||
msleep(20);
|
||||
}
|
||||
|
||||
static void venc_enable_clocks(int enable)
|
||||
{
|
||||
if (enable)
|
||||
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_54M |
|
||||
DSS_CLK_96M);
|
||||
else
|
||||
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_54M |
|
||||
DSS_CLK_96M);
|
||||
}
|
||||
|
||||
static const struct venc_config *venc_timings_to_config(
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
if (memcmp(&omap_dss_pal_timings, timings, sizeof(*timings)) == 0)
|
||||
return &venc_config_pal_trm;
|
||||
|
||||
if (memcmp(&omap_dss_ntsc_timings, timings, sizeof(*timings)) == 0)
|
||||
return &venc_config_ntsc_trm;
|
||||
|
||||
BUG();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* driver */
|
||||
static int venc_panel_probe(struct omap_dss_device *dssdev)
|
||||
{
|
||||
dssdev->panel.timings = omap_dss_pal_timings;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void venc_panel_remove(struct omap_dss_device *dssdev)
|
||||
{
|
||||
}
|
||||
|
||||
static int venc_panel_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
/* wait couple of vsyncs until enabling the LCD */
|
||||
msleep(50);
|
||||
|
||||
if (dssdev->platform_enable)
|
||||
r = dssdev->platform_enable(dssdev);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void venc_panel_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
if (dssdev->platform_disable)
|
||||
dssdev->platform_disable(dssdev);
|
||||
|
||||
/* wait at least 5 vsyncs after disabling the LCD */
|
||||
|
||||
msleep(100);
|
||||
}
|
||||
|
||||
static int venc_panel_suspend(struct omap_dss_device *dssdev)
|
||||
{
|
||||
venc_panel_disable(dssdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int venc_panel_resume(struct omap_dss_device *dssdev)
|
||||
{
|
||||
return venc_panel_enable(dssdev);
|
||||
}
|
||||
|
||||
static struct omap_dss_driver venc_driver = {
|
||||
.probe = venc_panel_probe,
|
||||
.remove = venc_panel_remove,
|
||||
|
||||
.enable = venc_panel_enable,
|
||||
.disable = venc_panel_disable,
|
||||
.suspend = venc_panel_suspend,
|
||||
.resume = venc_panel_resume,
|
||||
|
||||
.driver = {
|
||||
.name = "venc",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
/* driver end */
|
||||
|
||||
|
||||
|
||||
int venc_init(struct platform_device *pdev)
|
||||
{
|
||||
u8 rev_id;
|
||||
|
||||
mutex_init(&venc.venc_lock);
|
||||
|
||||
venc.wss_data = 0;
|
||||
|
||||
venc.base = ioremap(VENC_BASE, SZ_1K);
|
||||
if (!venc.base) {
|
||||
DSSERR("can't ioremap VENC\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
venc.vdda_dac_reg = regulator_get(&pdev->dev, "vdda_dac");
|
||||
if (IS_ERR(venc.vdda_dac_reg)) {
|
||||
iounmap(venc.base);
|
||||
DSSERR("can't get VDDA_DAC regulator\n");
|
||||
return PTR_ERR(venc.vdda_dac_reg);
|
||||
}
|
||||
|
||||
venc_enable_clocks(1);
|
||||
|
||||
rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff);
|
||||
printk(KERN_INFO "OMAP VENC rev %d\n", rev_id);
|
||||
|
||||
venc_enable_clocks(0);
|
||||
|
||||
return omap_dss_register_driver(&venc_driver);
|
||||
}
|
||||
|
||||
void venc_exit(void)
|
||||
{
|
||||
omap_dss_unregister_driver(&venc_driver);
|
||||
|
||||
regulator_put(venc.vdda_dac_reg);
|
||||
|
||||
iounmap(venc.base);
|
||||
}
|
||||
|
||||
static void venc_power_on(struct omap_dss_device *dssdev)
|
||||
{
|
||||
u32 l;
|
||||
|
||||
venc_enable_clocks(1);
|
||||
|
||||
venc_reset();
|
||||
venc_write_config(venc_timings_to_config(&dssdev->panel.timings));
|
||||
|
||||
dss_set_venc_output(dssdev->phy.venc.type);
|
||||
dss_set_dac_pwrdn_bgz(1);
|
||||
|
||||
l = 0;
|
||||
|
||||
if (dssdev->phy.venc.type == OMAP_DSS_VENC_TYPE_COMPOSITE)
|
||||
l |= 1 << 1;
|
||||
else /* S-Video */
|
||||
l |= (1 << 0) | (1 << 2);
|
||||
|
||||
if (dssdev->phy.venc.invert_polarity == false)
|
||||
l |= 1 << 3;
|
||||
|
||||
venc_write_reg(VENC_OUTPUT_CONTROL, l);
|
||||
|
||||
dispc_set_digit_size(dssdev->panel.timings.x_res,
|
||||
dssdev->panel.timings.y_res/2);
|
||||
|
||||
regulator_enable(venc.vdda_dac_reg);
|
||||
|
||||
if (dssdev->platform_enable)
|
||||
dssdev->platform_enable(dssdev);
|
||||
|
||||
dispc_enable_digit_out(1);
|
||||
}
|
||||
|
||||
static void venc_power_off(struct omap_dss_device *dssdev)
|
||||
{
|
||||
venc_write_reg(VENC_OUTPUT_CONTROL, 0);
|
||||
dss_set_dac_pwrdn_bgz(0);
|
||||
|
||||
dispc_enable_digit_out(0);
|
||||
|
||||
if (dssdev->platform_disable)
|
||||
dssdev->platform_disable(dssdev);
|
||||
|
||||
regulator_disable(venc.vdda_dac_reg);
|
||||
|
||||
venc_enable_clocks(0);
|
||||
}
|
||||
|
||||
static int venc_enable_display(struct omap_dss_device *dssdev)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
DSSDBG("venc_enable_display\n");
|
||||
|
||||
mutex_lock(&venc.venc_lock);
|
||||
|
||||
if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
|
||||
r = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
venc_power_on(dssdev);
|
||||
|
||||
venc.wss_data = 0;
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
|
||||
err:
|
||||
mutex_unlock(&venc.venc_lock);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void venc_disable_display(struct omap_dss_device *dssdev)
|
||||
{
|
||||
DSSDBG("venc_disable_display\n");
|
||||
|
||||
mutex_lock(&venc.venc_lock);
|
||||
|
||||
if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED)
|
||||
goto end;
|
||||
|
||||
if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) {
|
||||
/* suspended is the same as disabled with venc */
|
||||
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
|
||||
goto end;
|
||||
}
|
||||
|
||||
venc_power_off(dssdev);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
|
||||
end:
|
||||
mutex_unlock(&venc.venc_lock);
|
||||
}
|
||||
|
||||
static int venc_display_suspend(struct omap_dss_device *dssdev)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
DSSDBG("venc_display_suspend\n");
|
||||
|
||||
mutex_lock(&venc.venc_lock);
|
||||
|
||||
if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
|
||||
r = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
venc_power_off(dssdev);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
|
||||
err:
|
||||
mutex_unlock(&venc.venc_lock);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int venc_display_resume(struct omap_dss_device *dssdev)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
DSSDBG("venc_display_resume\n");
|
||||
|
||||
mutex_lock(&venc.venc_lock);
|
||||
|
||||
if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) {
|
||||
r = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
venc_power_on(dssdev);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
|
||||
err:
|
||||
mutex_unlock(&venc.venc_lock);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void venc_get_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
*timings = dssdev->panel.timings;
|
||||
}
|
||||
|
||||
static void venc_set_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
DSSDBG("venc_set_timings\n");
|
||||
|
||||
/* Reset WSS data when the TV standard changes. */
|
||||
if (memcmp(&dssdev->panel.timings, timings, sizeof(*timings)))
|
||||
venc.wss_data = 0;
|
||||
|
||||
dssdev->panel.timings = *timings;
|
||||
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
|
||||
/* turn the venc off and on to get new timings to use */
|
||||
venc_disable_display(dssdev);
|
||||
venc_enable_display(dssdev);
|
||||
}
|
||||
}
|
||||
|
||||
static int venc_check_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
DSSDBG("venc_check_timings\n");
|
||||
|
||||
if (memcmp(&omap_dss_pal_timings, timings, sizeof(*timings)) == 0)
|
||||
return 0;
|
||||
|
||||
if (memcmp(&omap_dss_ntsc_timings, timings, sizeof(*timings)) == 0)
|
||||
return 0;
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static u32 venc_get_wss(struct omap_dss_device *dssdev)
|
||||
{
|
||||
/* Invert due to VENC_L21_WC_CTL:INV=1 */
|
||||
return (venc.wss_data >> 8) ^ 0xfffff;
|
||||
}
|
||||
|
||||
static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss)
|
||||
{
|
||||
const struct venc_config *config;
|
||||
|
||||
DSSDBG("venc_set_wss\n");
|
||||
|
||||
mutex_lock(&venc.venc_lock);
|
||||
|
||||
config = venc_timings_to_config(&dssdev->panel.timings);
|
||||
|
||||
/* Invert due to VENC_L21_WC_CTL:INV=1 */
|
||||
venc.wss_data = (wss ^ 0xfffff) << 8;
|
||||
|
||||
venc_enable_clocks(1);
|
||||
|
||||
venc_write_reg(VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data |
|
||||
venc.wss_data);
|
||||
|
||||
venc_enable_clocks(0);
|
||||
|
||||
mutex_unlock(&venc.venc_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum omap_dss_update_mode venc_display_get_update_mode(
|
||||
struct omap_dss_device *dssdev)
|
||||
{
|
||||
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
|
||||
return OMAP_DSS_UPDATE_AUTO;
|
||||
else
|
||||
return OMAP_DSS_UPDATE_DISABLED;
|
||||
}
|
||||
|
||||
int venc_init_display(struct omap_dss_device *dssdev)
|
||||
{
|
||||
DSSDBG("init_display\n");
|
||||
|
||||
dssdev->enable = venc_enable_display;
|
||||
dssdev->disable = venc_disable_display;
|
||||
dssdev->suspend = venc_display_suspend;
|
||||
dssdev->resume = venc_display_resume;
|
||||
dssdev->get_timings = venc_get_timings;
|
||||
dssdev->set_timings = venc_set_timings;
|
||||
dssdev->check_timings = venc_check_timings;
|
||||
dssdev->get_wss = venc_get_wss;
|
||||
dssdev->set_wss = venc_set_wss;
|
||||
dssdev->get_update_mode = venc_display_get_update_mode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void venc_dump_regs(struct seq_file *s)
|
||||
{
|
||||
#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(r))
|
||||
|
||||
venc_enable_clocks(1);
|
||||
|
||||
DUMPREG(VENC_F_CONTROL);
|
||||
DUMPREG(VENC_VIDOUT_CTRL);
|
||||
DUMPREG(VENC_SYNC_CTRL);
|
||||
DUMPREG(VENC_LLEN);
|
||||
DUMPREG(VENC_FLENS);
|
||||
DUMPREG(VENC_HFLTR_CTRL);
|
||||
DUMPREG(VENC_CC_CARR_WSS_CARR);
|
||||
DUMPREG(VENC_C_PHASE);
|
||||
DUMPREG(VENC_GAIN_U);
|
||||
DUMPREG(VENC_GAIN_V);
|
||||
DUMPREG(VENC_GAIN_Y);
|
||||
DUMPREG(VENC_BLACK_LEVEL);
|
||||
DUMPREG(VENC_BLANK_LEVEL);
|
||||
DUMPREG(VENC_X_COLOR);
|
||||
DUMPREG(VENC_M_CONTROL);
|
||||
DUMPREG(VENC_BSTAMP_WSS_DATA);
|
||||
DUMPREG(VENC_S_CARR);
|
||||
DUMPREG(VENC_LINE21);
|
||||
DUMPREG(VENC_LN_SEL);
|
||||
DUMPREG(VENC_L21__WC_CTL);
|
||||
DUMPREG(VENC_HTRIGGER_VTRIGGER);
|
||||
DUMPREG(VENC_SAVID__EAVID);
|
||||
DUMPREG(VENC_FLEN__FAL);
|
||||
DUMPREG(VENC_LAL__PHASE_RESET);
|
||||
DUMPREG(VENC_HS_INT_START_STOP_X);
|
||||
DUMPREG(VENC_HS_EXT_START_STOP_X);
|
||||
DUMPREG(VENC_VS_INT_START_X);
|
||||
DUMPREG(VENC_VS_INT_STOP_X__VS_INT_START_Y);
|
||||
DUMPREG(VENC_VS_INT_STOP_Y__VS_EXT_START_X);
|
||||
DUMPREG(VENC_VS_EXT_STOP_X__VS_EXT_START_Y);
|
||||
DUMPREG(VENC_VS_EXT_STOP_Y);
|
||||
DUMPREG(VENC_AVID_START_STOP_X);
|
||||
DUMPREG(VENC_AVID_START_STOP_Y);
|
||||
DUMPREG(VENC_FID_INT_START_X__FID_INT_START_Y);
|
||||
DUMPREG(VENC_FID_INT_OFFSET_Y__FID_EXT_START_X);
|
||||
DUMPREG(VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y);
|
||||
DUMPREG(VENC_TVDETGP_INT_START_STOP_X);
|
||||
DUMPREG(VENC_TVDETGP_INT_START_STOP_Y);
|
||||
DUMPREG(VENC_GEN_CTRL);
|
||||
DUMPREG(VENC_OUTPUT_CONTROL);
|
||||
DUMPREG(VENC_OUTPUT_TEST);
|
||||
|
||||
venc_enable_clocks(0);
|
||||
|
||||
#undef DUMPREG
|
||||
}
|
37
drivers/video/omap2/omapfb/Kconfig
Normal file
37
drivers/video/omap2/omapfb/Kconfig
Normal file
@ -0,0 +1,37 @@
|
||||
menuconfig FB_OMAP2
|
||||
tristate "OMAP2/3 frame buffer support (EXPERIMENTAL)"
|
||||
depends on FB && OMAP2_DSS
|
||||
|
||||
select OMAP2_VRAM
|
||||
select OMAP2_VRFB
|
||||
select FB_CFB_FILLRECT
|
||||
select FB_CFB_COPYAREA
|
||||
select FB_CFB_IMAGEBLIT
|
||||
help
|
||||
Frame buffer driver for OMAP2/3 based boards.
|
||||
|
||||
config FB_OMAP2_DEBUG_SUPPORT
|
||||
bool "Debug support for OMAP2/3 FB"
|
||||
default y
|
||||
depends on FB_OMAP2
|
||||
help
|
||||
Support for debug output. You have to enable the actual printing
|
||||
with debug module parameter.
|
||||
|
||||
config FB_OMAP2_FORCE_AUTO_UPDATE
|
||||
bool "Force main display to automatic update mode"
|
||||
depends on FB_OMAP2
|
||||
help
|
||||
Forces main display to automatic update mode (if possible),
|
||||
and also enables tearsync (if possible). By default
|
||||
displays that support manual update are started in manual
|
||||
update mode.
|
||||
|
||||
config FB_OMAP2_NUM_FBS
|
||||
int "Number of framebuffers"
|
||||
range 1 10
|
||||
default 3
|
||||
depends on FB_OMAP2
|
||||
help
|
||||
Select the number of framebuffers created. OMAP2/3 has 3 overlays
|
||||
so normally this would be 3.
|
2
drivers/video/omap2/omapfb/Makefile
Normal file
2
drivers/video/omap2/omapfb/Makefile
Normal file
@ -0,0 +1,2 @@
|
||||
obj-$(CONFIG_FB_OMAP2) += omapfb.o
|
||||
omapfb-y := omapfb-main.o omapfb-sysfs.o omapfb-ioctl.o
|
755
drivers/video/omap2/omapfb/omapfb-ioctl.c
Normal file
755
drivers/video/omap2/omapfb/omapfb-ioctl.c
Normal file
@ -0,0 +1,755 @@
|
||||
/*
|
||||
* linux/drivers/video/omap2/omapfb-ioctl.c
|
||||
*
|
||||
* Copyright (C) 2008 Nokia Corporation
|
||||
* Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
|
||||
*
|
||||
* Some code and ideas taken from drivers/video/omap/ driver
|
||||
* by Imre Deak.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/fb.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/omapfb.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include <plat/display.h>
|
||||
#include <plat/vrfb.h>
|
||||
#include <plat/vram.h>
|
||||
|
||||
#include "omapfb.h"
|
||||
|
||||
static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
|
||||
{
|
||||
struct omapfb_info *ofbi = FB2OFB(fbi);
|
||||
struct omapfb2_device *fbdev = ofbi->fbdev;
|
||||
struct omap_overlay *ovl;
|
||||
struct omap_overlay_info info;
|
||||
int r = 0;
|
||||
|
||||
DBG("omapfb_setup_plane\n");
|
||||
|
||||
if (ofbi->num_overlays != 1) {
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* XXX uses only the first overlay */
|
||||
ovl = ofbi->overlays[0];
|
||||
|
||||
if (pi->enabled && !ofbi->region.size) {
|
||||
/*
|
||||
* This plane's memory was freed, can't enable it
|
||||
* until it's reallocated.
|
||||
*/
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ovl->get_overlay_info(ovl, &info);
|
||||
|
||||
info.pos_x = pi->pos_x;
|
||||
info.pos_y = pi->pos_y;
|
||||
info.out_width = pi->out_width;
|
||||
info.out_height = pi->out_height;
|
||||
info.enabled = pi->enabled;
|
||||
|
||||
r = ovl->set_overlay_info(ovl, &info);
|
||||
if (r)
|
||||
goto out;
|
||||
|
||||
if (ovl->manager) {
|
||||
r = ovl->manager->apply(ovl->manager);
|
||||
if (r)
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
if (r)
|
||||
dev_err(fbdev->dev, "setup_plane failed\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
|
||||
{
|
||||
struct omapfb_info *ofbi = FB2OFB(fbi);
|
||||
|
||||
if (ofbi->num_overlays != 1) {
|
||||
memset(pi, 0, sizeof(*pi));
|
||||
} else {
|
||||
struct omap_overlay_info *ovli;
|
||||
struct omap_overlay *ovl;
|
||||
|
||||
ovl = ofbi->overlays[0];
|
||||
ovli = &ovl->info;
|
||||
|
||||
pi->pos_x = ovli->pos_x;
|
||||
pi->pos_y = ovli->pos_y;
|
||||
pi->enabled = ovli->enabled;
|
||||
pi->channel_out = 0; /* xxx */
|
||||
pi->mirror = 0;
|
||||
pi->out_width = ovli->out_width;
|
||||
pi->out_height = ovli->out_height;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
|
||||
{
|
||||
struct omapfb_info *ofbi = FB2OFB(fbi);
|
||||
struct omapfb2_device *fbdev = ofbi->fbdev;
|
||||
struct omapfb2_mem_region *rg;
|
||||
int r, i;
|
||||
size_t size;
|
||||
|
||||
if (mi->type > OMAPFB_MEMTYPE_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
size = PAGE_ALIGN(mi->size);
|
||||
|
||||
rg = &ofbi->region;
|
||||
|
||||
for (i = 0; i < ofbi->num_overlays; i++) {
|
||||
if (ofbi->overlays[i]->info.enabled)
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (rg->size != size || rg->type != mi->type) {
|
||||
r = omapfb_realloc_fbmem(fbi, size, mi->type);
|
||||
if (r) {
|
||||
dev_err(fbdev->dev, "realloc fbmem failed\n");
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
|
||||
{
|
||||
struct omapfb_info *ofbi = FB2OFB(fbi);
|
||||
struct omapfb2_mem_region *rg;
|
||||
|
||||
rg = &ofbi->region;
|
||||
memset(mi, 0, sizeof(*mi));
|
||||
|
||||
mi->size = rg->size;
|
||||
mi->type = rg->type;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int omapfb_update_window_nolock(struct fb_info *fbi,
|
||||
u32 x, u32 y, u32 w, u32 h)
|
||||
{
|
||||
struct omap_dss_device *display = fb2display(fbi);
|
||||
u16 dw, dh;
|
||||
|
||||
if (!display)
|
||||
return 0;
|
||||
|
||||
if (w == 0 || h == 0)
|
||||
return 0;
|
||||
|
||||
display->get_resolution(display, &dw, &dh);
|
||||
|
||||
if (x + w > dw || y + h > dh)
|
||||
return -EINVAL;
|
||||
|
||||
return display->update(display, x, y, w, h);
|
||||
}
|
||||
|
||||
/* This function is exported for SGX driver use */
|
||||
int omapfb_update_window(struct fb_info *fbi,
|
||||
u32 x, u32 y, u32 w, u32 h)
|
||||
{
|
||||
struct omapfb_info *ofbi = FB2OFB(fbi);
|
||||
struct omapfb2_device *fbdev = ofbi->fbdev;
|
||||
int r;
|
||||
|
||||
omapfb_lock(fbdev);
|
||||
lock_fb_info(fbi);
|
||||
|
||||
r = omapfb_update_window_nolock(fbi, x, y, w, h);
|
||||
|
||||
unlock_fb_info(fbi);
|
||||
omapfb_unlock(fbdev);
|
||||
|
||||
return r;
|
||||
}
|
||||
EXPORT_SYMBOL(omapfb_update_window);
|
||||
|
||||
static int omapfb_set_update_mode(struct fb_info *fbi,
|
||||
enum omapfb_update_mode mode)
|
||||
{
|
||||
struct omap_dss_device *display = fb2display(fbi);
|
||||
enum omap_dss_update_mode um;
|
||||
int r;
|
||||
|
||||
if (!display || !display->set_update_mode)
|
||||
return -EINVAL;
|
||||
|
||||
switch (mode) {
|
||||
case OMAPFB_UPDATE_DISABLED:
|
||||
um = OMAP_DSS_UPDATE_DISABLED;
|
||||
break;
|
||||
|
||||
case OMAPFB_AUTO_UPDATE:
|
||||
um = OMAP_DSS_UPDATE_AUTO;
|
||||
break;
|
||||
|
||||
case OMAPFB_MANUAL_UPDATE:
|
||||
um = OMAP_DSS_UPDATE_MANUAL;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = display->set_update_mode(display, um);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int omapfb_get_update_mode(struct fb_info *fbi,
|
||||
enum omapfb_update_mode *mode)
|
||||
{
|
||||
struct omap_dss_device *display = fb2display(fbi);
|
||||
enum omap_dss_update_mode m;
|
||||
|
||||
if (!display || !display->get_update_mode)
|
||||
return -EINVAL;
|
||||
|
||||
m = display->get_update_mode(display);
|
||||
|
||||
switch (m) {
|
||||
case OMAP_DSS_UPDATE_DISABLED:
|
||||
*mode = OMAPFB_UPDATE_DISABLED;
|
||||
break;
|
||||
case OMAP_DSS_UPDATE_AUTO:
|
||||
*mode = OMAPFB_AUTO_UPDATE;
|
||||
break;
|
||||
case OMAP_DSS_UPDATE_MANUAL:
|
||||
*mode = OMAPFB_MANUAL_UPDATE;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* XXX this color key handling is a hack... */
|
||||
static struct omapfb_color_key omapfb_color_keys[2];
|
||||
|
||||
static int _omapfb_set_color_key(struct omap_overlay_manager *mgr,
|
||||
struct omapfb_color_key *ck)
|
||||
{
|
||||
struct omap_overlay_manager_info info;
|
||||
enum omap_dss_trans_key_type kt;
|
||||
int r;
|
||||
|
||||
mgr->get_manager_info(mgr, &info);
|
||||
|
||||
if (ck->key_type == OMAPFB_COLOR_KEY_DISABLED) {
|
||||
info.trans_enabled = false;
|
||||
omapfb_color_keys[mgr->id] = *ck;
|
||||
|
||||
r = mgr->set_manager_info(mgr, &info);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = mgr->apply(mgr);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
switch (ck->key_type) {
|
||||
case OMAPFB_COLOR_KEY_GFX_DST:
|
||||
kt = OMAP_DSS_COLOR_KEY_GFX_DST;
|
||||
break;
|
||||
case OMAPFB_COLOR_KEY_VID_SRC:
|
||||
kt = OMAP_DSS_COLOR_KEY_VID_SRC;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
info.default_color = ck->background;
|
||||
info.trans_key = ck->trans_key;
|
||||
info.trans_key_type = kt;
|
||||
info.trans_enabled = true;
|
||||
|
||||
omapfb_color_keys[mgr->id] = *ck;
|
||||
|
||||
r = mgr->set_manager_info(mgr, &info);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = mgr->apply(mgr);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int omapfb_set_color_key(struct fb_info *fbi,
|
||||
struct omapfb_color_key *ck)
|
||||
{
|
||||
struct omapfb_info *ofbi = FB2OFB(fbi);
|
||||
struct omapfb2_device *fbdev = ofbi->fbdev;
|
||||
int r;
|
||||
int i;
|
||||
struct omap_overlay_manager *mgr = NULL;
|
||||
|
||||
omapfb_lock(fbdev);
|
||||
|
||||
for (i = 0; i < ofbi->num_overlays; i++) {
|
||||
if (ofbi->overlays[i]->manager) {
|
||||
mgr = ofbi->overlays[i]->manager;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mgr) {
|
||||
r = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
r = _omapfb_set_color_key(mgr, ck);
|
||||
err:
|
||||
omapfb_unlock(fbdev);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int omapfb_get_color_key(struct fb_info *fbi,
|
||||
struct omapfb_color_key *ck)
|
||||
{
|
||||
struct omapfb_info *ofbi = FB2OFB(fbi);
|
||||
struct omapfb2_device *fbdev = ofbi->fbdev;
|
||||
struct omap_overlay_manager *mgr = NULL;
|
||||
int r = 0;
|
||||
int i;
|
||||
|
||||
omapfb_lock(fbdev);
|
||||
|
||||
for (i = 0; i < ofbi->num_overlays; i++) {
|
||||
if (ofbi->overlays[i]->manager) {
|
||||
mgr = ofbi->overlays[i]->manager;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mgr) {
|
||||
r = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
*ck = omapfb_color_keys[mgr->id];
|
||||
err:
|
||||
omapfb_unlock(fbdev);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int omapfb_memory_read(struct fb_info *fbi,
|
||||
struct omapfb_memory_read *mr)
|
||||
{
|
||||
struct omap_dss_device *display = fb2display(fbi);
|
||||
void *buf;
|
||||
int r;
|
||||
|
||||
if (!display || !display->memory_read)
|
||||
return -ENOENT;
|
||||
|
||||
if (!access_ok(VERIFY_WRITE, mr->buffer, mr->buffer_size))
|
||||
return -EFAULT;
|
||||
|
||||
if (mr->w * mr->h * 3 > mr->buffer_size)
|
||||
return -EINVAL;
|
||||
|
||||
buf = vmalloc(mr->buffer_size);
|
||||
if (!buf) {
|
||||
DBG("vmalloc failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
r = display->memory_read(display, buf, mr->buffer_size,
|
||||
mr->x, mr->y, mr->w, mr->h);
|
||||
|
||||
if (r > 0) {
|
||||
if (copy_to_user(mr->buffer, buf, mr->buffer_size))
|
||||
r = -EFAULT;
|
||||
}
|
||||
|
||||
vfree(buf);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int omapfb_get_ovl_colormode(struct omapfb2_device *fbdev,
|
||||
struct omapfb_ovl_colormode *mode)
|
||||
{
|
||||
int ovl_idx = mode->overlay_idx;
|
||||
int mode_idx = mode->mode_idx;
|
||||
struct omap_overlay *ovl;
|
||||
enum omap_color_mode supported_modes;
|
||||
struct fb_var_screeninfo var;
|
||||
int i;
|
||||
|
||||
if (ovl_idx >= fbdev->num_overlays)
|
||||
return -ENODEV;
|
||||
ovl = fbdev->overlays[ovl_idx];
|
||||
supported_modes = ovl->supported_modes;
|
||||
|
||||
mode_idx = mode->mode_idx;
|
||||
|
||||
for (i = 0; i < sizeof(supported_modes) * 8; i++) {
|
||||
if (!(supported_modes & (1 << i)))
|
||||
continue;
|
||||
/*
|
||||
* It's possible that the FB doesn't support a mode
|
||||
* that is supported by the overlay, so call the
|
||||
* following here.
|
||||
*/
|
||||
if (dss_mode_to_fb_mode(1 << i, &var) < 0)
|
||||
continue;
|
||||
|
||||
mode_idx--;
|
||||
if (mode_idx < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == sizeof(supported_modes) * 8)
|
||||
return -ENOENT;
|
||||
|
||||
mode->bits_per_pixel = var.bits_per_pixel;
|
||||
mode->nonstd = var.nonstd;
|
||||
mode->red = var.red;
|
||||
mode->green = var.green;
|
||||
mode->blue = var.blue;
|
||||
mode->transp = var.transp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int omapfb_wait_for_go(struct fb_info *fbi)
|
||||
{
|
||||
struct omapfb_info *ofbi = FB2OFB(fbi);
|
||||
int r = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ofbi->num_overlays; ++i) {
|
||||
struct omap_overlay *ovl = ofbi->overlays[i];
|
||||
r = ovl->wait_for_go(ovl);
|
||||
if (r)
|
||||
break;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct omapfb_info *ofbi = FB2OFB(fbi);
|
||||
struct omapfb2_device *fbdev = ofbi->fbdev;
|
||||
struct omap_dss_device *display = fb2display(fbi);
|
||||
|
||||
union {
|
||||
struct omapfb_update_window_old uwnd_o;
|
||||
struct omapfb_update_window uwnd;
|
||||
struct omapfb_plane_info plane_info;
|
||||
struct omapfb_caps caps;
|
||||
struct omapfb_mem_info mem_info;
|
||||
struct omapfb_color_key color_key;
|
||||
struct omapfb_ovl_colormode ovl_colormode;
|
||||
enum omapfb_update_mode update_mode;
|
||||
int test_num;
|
||||
struct omapfb_memory_read memory_read;
|
||||
struct omapfb_vram_info vram_info;
|
||||
struct omapfb_tearsync_info tearsync_info;
|
||||
} p;
|
||||
|
||||
int r = 0;
|
||||
|
||||
switch (cmd) {
|
||||
case OMAPFB_SYNC_GFX:
|
||||
DBG("ioctl SYNC_GFX\n");
|
||||
if (!display || !display->sync) {
|
||||
/* DSS1 never returns an error here, so we neither */
|
||||
/*r = -EINVAL;*/
|
||||
break;
|
||||
}
|
||||
|
||||
r = display->sync(display);
|
||||
break;
|
||||
|
||||
case OMAPFB_UPDATE_WINDOW_OLD:
|
||||
DBG("ioctl UPDATE_WINDOW_OLD\n");
|
||||
if (!display || !display->update) {
|
||||
r = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (copy_from_user(&p.uwnd_o,
|
||||
(void __user *)arg,
|
||||
sizeof(p.uwnd_o))) {
|
||||
r = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
r = omapfb_update_window_nolock(fbi, p.uwnd_o.x, p.uwnd_o.y,
|
||||
p.uwnd_o.width, p.uwnd_o.height);
|
||||
break;
|
||||
|
||||
case OMAPFB_UPDATE_WINDOW:
|
||||
DBG("ioctl UPDATE_WINDOW\n");
|
||||
if (!display || !display->update) {
|
||||
r = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (copy_from_user(&p.uwnd, (void __user *)arg,
|
||||
sizeof(p.uwnd))) {
|
||||
r = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
r = omapfb_update_window_nolock(fbi, p.uwnd.x, p.uwnd.y,
|
||||
p.uwnd.width, p.uwnd.height);
|
||||
break;
|
||||
|
||||
case OMAPFB_SETUP_PLANE:
|
||||
DBG("ioctl SETUP_PLANE\n");
|
||||
if (copy_from_user(&p.plane_info, (void __user *)arg,
|
||||
sizeof(p.plane_info)))
|
||||
r = -EFAULT;
|
||||
else
|
||||
r = omapfb_setup_plane(fbi, &p.plane_info);
|
||||
break;
|
||||
|
||||
case OMAPFB_QUERY_PLANE:
|
||||
DBG("ioctl QUERY_PLANE\n");
|
||||
r = omapfb_query_plane(fbi, &p.plane_info);
|
||||
if (r < 0)
|
||||
break;
|
||||
if (copy_to_user((void __user *)arg, &p.plane_info,
|
||||
sizeof(p.plane_info)))
|
||||
r = -EFAULT;
|
||||
break;
|
||||
|
||||
case OMAPFB_SETUP_MEM:
|
||||
DBG("ioctl SETUP_MEM\n");
|
||||
if (copy_from_user(&p.mem_info, (void __user *)arg,
|
||||
sizeof(p.mem_info)))
|
||||
r = -EFAULT;
|
||||
else
|
||||
r = omapfb_setup_mem(fbi, &p.mem_info);
|
||||
break;
|
||||
|
||||
case OMAPFB_QUERY_MEM:
|
||||
DBG("ioctl QUERY_MEM\n");
|
||||
r = omapfb_query_mem(fbi, &p.mem_info);
|
||||
if (r < 0)
|
||||
break;
|
||||
if (copy_to_user((void __user *)arg, &p.mem_info,
|
||||
sizeof(p.mem_info)))
|
||||
r = -EFAULT;
|
||||
break;
|
||||
|
||||
case OMAPFB_GET_CAPS:
|
||||
DBG("ioctl GET_CAPS\n");
|
||||
if (!display) {
|
||||
r = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
memset(&p.caps, 0, sizeof(p.caps));
|
||||
if (display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE)
|
||||
p.caps.ctrl |= OMAPFB_CAPS_MANUAL_UPDATE;
|
||||
if (display->caps & OMAP_DSS_DISPLAY_CAP_TEAR_ELIM)
|
||||
p.caps.ctrl |= OMAPFB_CAPS_TEARSYNC;
|
||||
|
||||
if (copy_to_user((void __user *)arg, &p.caps, sizeof(p.caps)))
|
||||
r = -EFAULT;
|
||||
break;
|
||||
|
||||
case OMAPFB_GET_OVERLAY_COLORMODE:
|
||||
DBG("ioctl GET_OVERLAY_COLORMODE\n");
|
||||
if (copy_from_user(&p.ovl_colormode, (void __user *)arg,
|
||||
sizeof(p.ovl_colormode))) {
|
||||
r = -EFAULT;
|
||||
break;
|
||||
}
|
||||
r = omapfb_get_ovl_colormode(fbdev, &p.ovl_colormode);
|
||||
if (r < 0)
|
||||
break;
|
||||
if (copy_to_user((void __user *)arg, &p.ovl_colormode,
|
||||
sizeof(p.ovl_colormode)))
|
||||
r = -EFAULT;
|
||||
break;
|
||||
|
||||
case OMAPFB_SET_UPDATE_MODE:
|
||||
DBG("ioctl SET_UPDATE_MODE\n");
|
||||
if (get_user(p.update_mode, (int __user *)arg))
|
||||
r = -EFAULT;
|
||||
else
|
||||
r = omapfb_set_update_mode(fbi, p.update_mode);
|
||||
break;
|
||||
|
||||
case OMAPFB_GET_UPDATE_MODE:
|
||||
DBG("ioctl GET_UPDATE_MODE\n");
|
||||
r = omapfb_get_update_mode(fbi, &p.update_mode);
|
||||
if (r)
|
||||
break;
|
||||
if (put_user(p.update_mode,
|
||||
(enum omapfb_update_mode __user *)arg))
|
||||
r = -EFAULT;
|
||||
break;
|
||||
|
||||
case OMAPFB_SET_COLOR_KEY:
|
||||
DBG("ioctl SET_COLOR_KEY\n");
|
||||
if (copy_from_user(&p.color_key, (void __user *)arg,
|
||||
sizeof(p.color_key)))
|
||||
r = -EFAULT;
|
||||
else
|
||||
r = omapfb_set_color_key(fbi, &p.color_key);
|
||||
break;
|
||||
|
||||
case OMAPFB_GET_COLOR_KEY:
|
||||
DBG("ioctl GET_COLOR_KEY\n");
|
||||
r = omapfb_get_color_key(fbi, &p.color_key);
|
||||
if (r)
|
||||
break;
|
||||
if (copy_to_user((void __user *)arg, &p.color_key,
|
||||
sizeof(p.color_key)))
|
||||
r = -EFAULT;
|
||||
break;
|
||||
|
||||
case OMAPFB_WAITFORVSYNC:
|
||||
DBG("ioctl WAITFORVSYNC\n");
|
||||
if (!display) {
|
||||
r = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
r = display->wait_vsync(display);
|
||||
break;
|
||||
|
||||
case OMAPFB_WAITFORGO:
|
||||
DBG("ioctl WAITFORGO\n");
|
||||
if (!display) {
|
||||
r = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
r = omapfb_wait_for_go(fbi);
|
||||
break;
|
||||
|
||||
/* LCD and CTRL tests do the same thing for backward
|
||||
* compatibility */
|
||||
case OMAPFB_LCD_TEST:
|
||||
DBG("ioctl LCD_TEST\n");
|
||||
if (get_user(p.test_num, (int __user *)arg)) {
|
||||
r = -EFAULT;
|
||||
break;
|
||||
}
|
||||
if (!display || !display->run_test) {
|
||||
r = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
r = display->run_test(display, p.test_num);
|
||||
|
||||
break;
|
||||
|
||||
case OMAPFB_CTRL_TEST:
|
||||
DBG("ioctl CTRL_TEST\n");
|
||||
if (get_user(p.test_num, (int __user *)arg)) {
|
||||
r = -EFAULT;
|
||||
break;
|
||||
}
|
||||
if (!display || !display->run_test) {
|
||||
r = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
r = display->run_test(display, p.test_num);
|
||||
|
||||
break;
|
||||
|
||||
case OMAPFB_MEMORY_READ:
|
||||
DBG("ioctl MEMORY_READ\n");
|
||||
|
||||
if (copy_from_user(&p.memory_read, (void __user *)arg,
|
||||
sizeof(p.memory_read))) {
|
||||
r = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
r = omapfb_memory_read(fbi, &p.memory_read);
|
||||
|
||||
break;
|
||||
|
||||
case OMAPFB_GET_VRAM_INFO: {
|
||||
unsigned long vram, free, largest;
|
||||
|
||||
DBG("ioctl GET_VRAM_INFO\n");
|
||||
|
||||
omap_vram_get_info(&vram, &free, &largest);
|
||||
p.vram_info.total = vram;
|
||||
p.vram_info.free = free;
|
||||
p.vram_info.largest_free_block = largest;
|
||||
|
||||
if (copy_to_user((void __user *)arg, &p.vram_info,
|
||||
sizeof(p.vram_info)))
|
||||
r = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
case OMAPFB_SET_TEARSYNC: {
|
||||
DBG("ioctl SET_TEARSYNC\n");
|
||||
|
||||
if (copy_from_user(&p.tearsync_info, (void __user *)arg,
|
||||
sizeof(p.tearsync_info))) {
|
||||
r = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!display->enable_te) {
|
||||
r = -ENODEV;
|
||||
break;
|
||||
}
|
||||
|
||||
r = display->enable_te(display, !!p.tearsync_info.enabled);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
dev_err(fbdev->dev, "Unknown ioctl 0x%x\n", cmd);
|
||||
r = -EINVAL;
|
||||
}
|
||||
|
||||
if (r < 0)
|
||||
DBG("ioctl failed: %d\n", r);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
2261
drivers/video/omap2/omapfb/omapfb-main.c
Normal file
2261
drivers/video/omap2/omapfb/omapfb-main.c
Normal file
File diff suppressed because it is too large
Load Diff
507
drivers/video/omap2/omapfb/omapfb-sysfs.c
Normal file
507
drivers/video/omap2/omapfb/omapfb-sysfs.c
Normal file
@ -0,0 +1,507 @@
|
||||
/*
|
||||
* linux/drivers/video/omap2/omapfb-sysfs.c
|
||||
*
|
||||
* Copyright (C) 2008 Nokia Corporation
|
||||
* Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
|
||||
*
|
||||
* Some code and ideas taken from drivers/video/omap/ driver
|
||||
* by Imre Deak.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/fb.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/omapfb.h>
|
||||
|
||||
#include <plat/display.h>
|
||||
#include <plat/vrfb.h>
|
||||
|
||||
#include "omapfb.h"
|
||||
|
||||
static ssize_t show_rotate_type(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct fb_info *fbi = dev_get_drvdata(dev);
|
||||
struct omapfb_info *ofbi = FB2OFB(fbi);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", ofbi->rotation_type);
|
||||
}
|
||||
|
||||
static ssize_t store_rotate_type(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct fb_info *fbi = dev_get_drvdata(dev);
|
||||
struct omapfb_info *ofbi = FB2OFB(fbi);
|
||||
enum omap_dss_rotation_type rot_type;
|
||||
int r;
|
||||
|
||||
rot_type = simple_strtoul(buf, NULL, 0);
|
||||
|
||||
if (rot_type != OMAP_DSS_ROT_DMA && rot_type != OMAP_DSS_ROT_VRFB)
|
||||
return -EINVAL;
|
||||
|
||||
lock_fb_info(fbi);
|
||||
|
||||
r = 0;
|
||||
if (rot_type == ofbi->rotation_type)
|
||||
goto out;
|
||||
|
||||
if (ofbi->region.size) {
|
||||
r = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ofbi->rotation_type = rot_type;
|
||||
|
||||
/*
|
||||
* Since the VRAM for this FB is not allocated at the moment we don't
|
||||
* need to do any further parameter checking at this point.
|
||||
*/
|
||||
out:
|
||||
unlock_fb_info(fbi);
|
||||
|
||||
return r ? r : count;
|
||||
}
|
||||
|
||||
|
||||
static ssize_t show_mirror(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct fb_info *fbi = dev_get_drvdata(dev);
|
||||
struct omapfb_info *ofbi = FB2OFB(fbi);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", ofbi->mirror);
|
||||
}
|
||||
|
||||
static ssize_t store_mirror(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct fb_info *fbi = dev_get_drvdata(dev);
|
||||
struct omapfb_info *ofbi = FB2OFB(fbi);
|
||||
bool mirror;
|
||||
int r;
|
||||
struct fb_var_screeninfo new_var;
|
||||
|
||||
mirror = simple_strtoul(buf, NULL, 0);
|
||||
|
||||
if (mirror != 0 && mirror != 1)
|
||||
return -EINVAL;
|
||||
|
||||
lock_fb_info(fbi);
|
||||
|
||||
ofbi->mirror = mirror;
|
||||
|
||||
memcpy(&new_var, &fbi->var, sizeof(new_var));
|
||||
r = check_fb_var(fbi, &new_var);
|
||||
if (r)
|
||||
goto out;
|
||||
memcpy(&fbi->var, &new_var, sizeof(fbi->var));
|
||||
|
||||
set_fb_fix(fbi);
|
||||
|
||||
r = omapfb_apply_changes(fbi, 0);
|
||||
if (r)
|
||||
goto out;
|
||||
|
||||
r = count;
|
||||
out:
|
||||
unlock_fb_info(fbi);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static ssize_t show_overlays(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct fb_info *fbi = dev_get_drvdata(dev);
|
||||
struct omapfb_info *ofbi = FB2OFB(fbi);
|
||||
struct omapfb2_device *fbdev = ofbi->fbdev;
|
||||
ssize_t l = 0;
|
||||
int t;
|
||||
|
||||
omapfb_lock(fbdev);
|
||||
lock_fb_info(fbi);
|
||||
|
||||
for (t = 0; t < ofbi->num_overlays; t++) {
|
||||
struct omap_overlay *ovl = ofbi->overlays[t];
|
||||
int ovlnum;
|
||||
|
||||
for (ovlnum = 0; ovlnum < fbdev->num_overlays; ++ovlnum)
|
||||
if (ovl == fbdev->overlays[ovlnum])
|
||||
break;
|
||||
|
||||
l += snprintf(buf + l, PAGE_SIZE - l, "%s%d",
|
||||
t == 0 ? "" : ",", ovlnum);
|
||||
}
|
||||
|
||||
l += snprintf(buf + l, PAGE_SIZE - l, "\n");
|
||||
|
||||
unlock_fb_info(fbi);
|
||||
omapfb_unlock(fbdev);
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
static struct omapfb_info *get_overlay_fb(struct omapfb2_device *fbdev,
|
||||
struct omap_overlay *ovl)
|
||||
{
|
||||
int i, t;
|
||||
|
||||
for (i = 0; i < fbdev->num_fbs; i++) {
|
||||
struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
|
||||
|
||||
for (t = 0; t < ofbi->num_overlays; t++) {
|
||||
if (ofbi->overlays[t] == ovl)
|
||||
return ofbi;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static ssize_t store_overlays(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct fb_info *fbi = dev_get_drvdata(dev);
|
||||
struct omapfb_info *ofbi = FB2OFB(fbi);
|
||||
struct omapfb2_device *fbdev = ofbi->fbdev;
|
||||
struct omap_overlay *ovls[OMAPFB_MAX_OVL_PER_FB];
|
||||
struct omap_overlay *ovl;
|
||||
int num_ovls, r, i;
|
||||
int len;
|
||||
bool added = false;
|
||||
|
||||
num_ovls = 0;
|
||||
|
||||
len = strlen(buf);
|
||||
if (buf[len - 1] == '\n')
|
||||
len = len - 1;
|
||||
|
||||
omapfb_lock(fbdev);
|
||||
lock_fb_info(fbi);
|
||||
|
||||
if (len > 0) {
|
||||
char *p = (char *)buf;
|
||||
int ovlnum;
|
||||
|
||||
while (p < buf + len) {
|
||||
int found;
|
||||
if (num_ovls == OMAPFB_MAX_OVL_PER_FB) {
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ovlnum = simple_strtoul(p, &p, 0);
|
||||
if (ovlnum > fbdev->num_overlays) {
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
found = 0;
|
||||
for (i = 0; i < num_ovls; ++i) {
|
||||
if (ovls[i] == fbdev->overlays[ovlnum]) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
ovls[num_ovls++] = fbdev->overlays[ovlnum];
|
||||
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < num_ovls; ++i) {
|
||||
struct omapfb_info *ofbi2 = get_overlay_fb(fbdev, ovls[i]);
|
||||
if (ofbi2 && ofbi2 != ofbi) {
|
||||
dev_err(fbdev->dev, "overlay already in use\n");
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* detach unused overlays */
|
||||
for (i = 0; i < ofbi->num_overlays; ++i) {
|
||||
int t, found;
|
||||
|
||||
ovl = ofbi->overlays[i];
|
||||
|
||||
found = 0;
|
||||
|
||||
for (t = 0; t < num_ovls; ++t) {
|
||||
if (ovl == ovls[t]) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found)
|
||||
continue;
|
||||
|
||||
DBG("detaching %d\n", ofbi->overlays[i]->id);
|
||||
|
||||
omapfb_overlay_enable(ovl, 0);
|
||||
|
||||
if (ovl->manager)
|
||||
ovl->manager->apply(ovl->manager);
|
||||
|
||||
for (t = i + 1; t < ofbi->num_overlays; t++) {
|
||||
ofbi->rotation[t-1] = ofbi->rotation[t];
|
||||
ofbi->overlays[t-1] = ofbi->overlays[t];
|
||||
}
|
||||
|
||||
ofbi->num_overlays--;
|
||||
i--;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_ovls; ++i) {
|
||||
int t, found;
|
||||
|
||||
ovl = ovls[i];
|
||||
|
||||
found = 0;
|
||||
|
||||
for (t = 0; t < ofbi->num_overlays; ++t) {
|
||||
if (ovl == ofbi->overlays[t]) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found)
|
||||
continue;
|
||||
ofbi->rotation[ofbi->num_overlays] = 0;
|
||||
ofbi->overlays[ofbi->num_overlays++] = ovl;
|
||||
|
||||
added = true;
|
||||
}
|
||||
|
||||
if (added) {
|
||||
r = omapfb_apply_changes(fbi, 0);
|
||||
if (r)
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = count;
|
||||
out:
|
||||
unlock_fb_info(fbi);
|
||||
omapfb_unlock(fbdev);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static ssize_t show_overlays_rotate(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct fb_info *fbi = dev_get_drvdata(dev);
|
||||
struct omapfb_info *ofbi = FB2OFB(fbi);
|
||||
ssize_t l = 0;
|
||||
int t;
|
||||
|
||||
lock_fb_info(fbi);
|
||||
|
||||
for (t = 0; t < ofbi->num_overlays; t++) {
|
||||
l += snprintf(buf + l, PAGE_SIZE - l, "%s%d",
|
||||
t == 0 ? "" : ",", ofbi->rotation[t]);
|
||||
}
|
||||
|
||||
l += snprintf(buf + l, PAGE_SIZE - l, "\n");
|
||||
|
||||
unlock_fb_info(fbi);
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
static ssize_t store_overlays_rotate(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct fb_info *fbi = dev_get_drvdata(dev);
|
||||
struct omapfb_info *ofbi = FB2OFB(fbi);
|
||||
int num_ovls = 0, r, i;
|
||||
int len;
|
||||
bool changed = false;
|
||||
u8 rotation[OMAPFB_MAX_OVL_PER_FB];
|
||||
|
||||
len = strlen(buf);
|
||||
if (buf[len - 1] == '\n')
|
||||
len = len - 1;
|
||||
|
||||
lock_fb_info(fbi);
|
||||
|
||||
if (len > 0) {
|
||||
char *p = (char *)buf;
|
||||
|
||||
while (p < buf + len) {
|
||||
int rot;
|
||||
|
||||
if (num_ovls == ofbi->num_overlays) {
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rot = simple_strtoul(p, &p, 0);
|
||||
if (rot < 0 || rot > 3) {
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ofbi->rotation[num_ovls] != rot)
|
||||
changed = true;
|
||||
|
||||
rotation[num_ovls++] = rot;
|
||||
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
if (num_ovls != ofbi->num_overlays) {
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
for (i = 0; i < num_ovls; ++i)
|
||||
ofbi->rotation[i] = rotation[i];
|
||||
|
||||
r = omapfb_apply_changes(fbi, 0);
|
||||
if (r)
|
||||
goto out;
|
||||
|
||||
/* FIXME error handling? */
|
||||
}
|
||||
|
||||
r = count;
|
||||
out:
|
||||
unlock_fb_info(fbi);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static ssize_t show_size(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct fb_info *fbi = dev_get_drvdata(dev);
|
||||
struct omapfb_info *ofbi = FB2OFB(fbi);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%lu\n", ofbi->region.size);
|
||||
}
|
||||
|
||||
static ssize_t store_size(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct fb_info *fbi = dev_get_drvdata(dev);
|
||||
struct omapfb_info *ofbi = FB2OFB(fbi);
|
||||
unsigned long size;
|
||||
int r;
|
||||
int i;
|
||||
|
||||
size = PAGE_ALIGN(simple_strtoul(buf, NULL, 0));
|
||||
|
||||
lock_fb_info(fbi);
|
||||
|
||||
for (i = 0; i < ofbi->num_overlays; i++) {
|
||||
if (ofbi->overlays[i]->info.enabled) {
|
||||
r = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (size != ofbi->region.size) {
|
||||
r = omapfb_realloc_fbmem(fbi, size, ofbi->region.type);
|
||||
if (r) {
|
||||
dev_err(dev, "realloc fbmem failed\n");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
r = count;
|
||||
out:
|
||||
unlock_fb_info(fbi);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static ssize_t show_phys(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct fb_info *fbi = dev_get_drvdata(dev);
|
||||
struct omapfb_info *ofbi = FB2OFB(fbi);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%0x\n", ofbi->region.paddr);
|
||||
}
|
||||
|
||||
static ssize_t show_virt(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct fb_info *fbi = dev_get_drvdata(dev);
|
||||
struct omapfb_info *ofbi = FB2OFB(fbi);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%p\n", ofbi->region.vaddr);
|
||||
}
|
||||
|
||||
static struct device_attribute omapfb_attrs[] = {
|
||||
__ATTR(rotate_type, S_IRUGO | S_IWUSR, show_rotate_type,
|
||||
store_rotate_type),
|
||||
__ATTR(mirror, S_IRUGO | S_IWUSR, show_mirror, store_mirror),
|
||||
__ATTR(size, S_IRUGO | S_IWUSR, show_size, store_size),
|
||||
__ATTR(overlays, S_IRUGO | S_IWUSR, show_overlays, store_overlays),
|
||||
__ATTR(overlays_rotate, S_IRUGO | S_IWUSR, show_overlays_rotate,
|
||||
store_overlays_rotate),
|
||||
__ATTR(phys_addr, S_IRUGO, show_phys, NULL),
|
||||
__ATTR(virt_addr, S_IRUGO, show_virt, NULL),
|
||||
};
|
||||
|
||||
int omapfb_create_sysfs(struct omapfb2_device *fbdev)
|
||||
{
|
||||
int i;
|
||||
int r;
|
||||
|
||||
DBG("create sysfs for fbs\n");
|
||||
for (i = 0; i < fbdev->num_fbs; i++) {
|
||||
int t;
|
||||
for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++) {
|
||||
r = device_create_file(fbdev->fbs[i]->dev,
|
||||
&omapfb_attrs[t]);
|
||||
|
||||
if (r) {
|
||||
dev_err(fbdev->dev, "failed to create sysfs "
|
||||
"file\n");
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void omapfb_remove_sysfs(struct omapfb2_device *fbdev)
|
||||
{
|
||||
int i, t;
|
||||
|
||||
DBG("remove sysfs for fbs\n");
|
||||
for (i = 0; i < fbdev->num_fbs; i++) {
|
||||
for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++)
|
||||
device_remove_file(fbdev->fbs[i]->dev,
|
||||
&omapfb_attrs[t]);
|
||||
}
|
||||
}
|
||||
|
146
drivers/video/omap2/omapfb/omapfb.h
Normal file
146
drivers/video/omap2/omapfb/omapfb.h
Normal file
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* linux/drivers/video/omap2/omapfb.h
|
||||
*
|
||||
* Copyright (C) 2008 Nokia Corporation
|
||||
* Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
|
||||
*
|
||||
* Some code and ideas taken from drivers/video/omap/ driver
|
||||
* by Imre Deak.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __DRIVERS_VIDEO_OMAP2_OMAPFB_H__
|
||||
#define __DRIVERS_VIDEO_OMAP2_OMAPFB_H__
|
||||
|
||||
#ifdef CONFIG_FB_OMAP2_DEBUG_SUPPORT
|
||||
#define DEBUG
|
||||
#endif
|
||||
|
||||
#include <plat/display.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
extern unsigned int omapfb_debug;
|
||||
#define DBG(format, ...) \
|
||||
if (omapfb_debug) \
|
||||
printk(KERN_DEBUG "OMAPFB: " format, ## __VA_ARGS__)
|
||||
#else
|
||||
#define DBG(format, ...)
|
||||
#endif
|
||||
|
||||
#define FB2OFB(fb_info) ((struct omapfb_info *)(fb_info->par))
|
||||
|
||||
/* max number of overlays to which a framebuffer data can be direct */
|
||||
#define OMAPFB_MAX_OVL_PER_FB 3
|
||||
|
||||
struct omapfb2_mem_region {
|
||||
u32 paddr;
|
||||
void __iomem *vaddr;
|
||||
struct vrfb vrfb;
|
||||
unsigned long size;
|
||||
u8 type; /* OMAPFB_PLANE_MEM_* */
|
||||
bool alloc; /* allocated by the driver */
|
||||
bool map; /* kernel mapped by the driver */
|
||||
};
|
||||
|
||||
/* appended to fb_info */
|
||||
struct omapfb_info {
|
||||
int id;
|
||||
struct omapfb2_mem_region region;
|
||||
atomic_t map_count;
|
||||
int num_overlays;
|
||||
struct omap_overlay *overlays[OMAPFB_MAX_OVL_PER_FB];
|
||||
struct omapfb2_device *fbdev;
|
||||
enum omap_dss_rotation_type rotation_type;
|
||||
u8 rotation[OMAPFB_MAX_OVL_PER_FB];
|
||||
bool mirror;
|
||||
};
|
||||
|
||||
struct omapfb2_device {
|
||||
struct device *dev;
|
||||
struct mutex mtx;
|
||||
|
||||
u32 pseudo_palette[17];
|
||||
|
||||
int state;
|
||||
|
||||
unsigned num_fbs;
|
||||
struct fb_info *fbs[10];
|
||||
|
||||
unsigned num_displays;
|
||||
struct omap_dss_device *displays[10];
|
||||
unsigned num_overlays;
|
||||
struct omap_overlay *overlays[10];
|
||||
unsigned num_managers;
|
||||
struct omap_overlay_manager *managers[10];
|
||||
};
|
||||
|
||||
struct omapfb_colormode {
|
||||
enum omap_color_mode dssmode;
|
||||
u32 bits_per_pixel;
|
||||
u32 nonstd;
|
||||
struct fb_bitfield red;
|
||||
struct fb_bitfield green;
|
||||
struct fb_bitfield blue;
|
||||
struct fb_bitfield transp;
|
||||
};
|
||||
|
||||
void set_fb_fix(struct fb_info *fbi);
|
||||
int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var);
|
||||
int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type);
|
||||
int omapfb_apply_changes(struct fb_info *fbi, int init);
|
||||
|
||||
int omapfb_create_sysfs(struct omapfb2_device *fbdev);
|
||||
void omapfb_remove_sysfs(struct omapfb2_device *fbdev);
|
||||
|
||||
int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg);
|
||||
|
||||
int dss_mode_to_fb_mode(enum omap_color_mode dssmode,
|
||||
struct fb_var_screeninfo *var);
|
||||
|
||||
/* find the display connected to this fb, if any */
|
||||
static inline struct omap_dss_device *fb2display(struct fb_info *fbi)
|
||||
{
|
||||
struct omapfb_info *ofbi = FB2OFB(fbi);
|
||||
int i;
|
||||
|
||||
/* XXX: returns the display connected to first attached overlay */
|
||||
for (i = 0; i < ofbi->num_overlays; i++) {
|
||||
if (ofbi->overlays[i]->manager)
|
||||
return ofbi->overlays[i]->manager->device;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void omapfb_lock(struct omapfb2_device *fbdev)
|
||||
{
|
||||
mutex_lock(&fbdev->mtx);
|
||||
}
|
||||
|
||||
static inline void omapfb_unlock(struct omapfb2_device *fbdev)
|
||||
{
|
||||
mutex_unlock(&fbdev->mtx);
|
||||
}
|
||||
|
||||
static inline int omapfb_overlay_enable(struct omap_overlay *ovl,
|
||||
int enable)
|
||||
{
|
||||
struct omap_overlay_info info;
|
||||
|
||||
ovl->get_overlay_info(ovl, &info);
|
||||
info.enabled = enable;
|
||||
return ovl->set_overlay_info(ovl, &info);
|
||||
}
|
||||
|
||||
#endif
|
655
drivers/video/omap2/vram.c
Normal file
655
drivers/video/omap2/vram.c
Normal file
@ -0,0 +1,655 @@
|
||||
/*
|
||||
* VRAM manager for OMAP
|
||||
*
|
||||
* Copyright (C) 2009 Nokia Corporation
|
||||
* Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/*#define DEBUG*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/bootmem.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <asm/setup.h>
|
||||
|
||||
#include <plat/sram.h>
|
||||
#include <plat/vram.h>
|
||||
#include <plat/dma.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DBG(format, ...) pr_debug("VRAM: " format, ## __VA_ARGS__)
|
||||
#else
|
||||
#define DBG(format, ...)
|
||||
#endif
|
||||
|
||||
#define OMAP2_SRAM_START 0x40200000
|
||||
/* Maximum size, in reality this is smaller if SRAM is partially locked. */
|
||||
#define OMAP2_SRAM_SIZE 0xa0000 /* 640k */
|
||||
|
||||
/* postponed regions are used to temporarily store region information at boot
|
||||
* time when we cannot yet allocate the region list */
|
||||
#define MAX_POSTPONED_REGIONS 10
|
||||
|
||||
static bool vram_initialized;
|
||||
static int postponed_cnt;
|
||||
static struct {
|
||||
unsigned long paddr;
|
||||
size_t size;
|
||||
} postponed_regions[MAX_POSTPONED_REGIONS];
|
||||
|
||||
struct vram_alloc {
|
||||
struct list_head list;
|
||||
unsigned long paddr;
|
||||
unsigned pages;
|
||||
};
|
||||
|
||||
struct vram_region {
|
||||
struct list_head list;
|
||||
struct list_head alloc_list;
|
||||
unsigned long paddr;
|
||||
unsigned pages;
|
||||
};
|
||||
|
||||
static DEFINE_MUTEX(region_mutex);
|
||||
static LIST_HEAD(region_list);
|
||||
|
||||
static inline int region_mem_type(unsigned long paddr)
|
||||
{
|
||||
if (paddr >= OMAP2_SRAM_START &&
|
||||
paddr < OMAP2_SRAM_START + OMAP2_SRAM_SIZE)
|
||||
return OMAP_VRAM_MEMTYPE_SRAM;
|
||||
else
|
||||
return OMAP_VRAM_MEMTYPE_SDRAM;
|
||||
}
|
||||
|
||||
static struct vram_region *omap_vram_create_region(unsigned long paddr,
|
||||
unsigned pages)
|
||||
{
|
||||
struct vram_region *rm;
|
||||
|
||||
rm = kzalloc(sizeof(*rm), GFP_KERNEL);
|
||||
|
||||
if (rm) {
|
||||
INIT_LIST_HEAD(&rm->alloc_list);
|
||||
rm->paddr = paddr;
|
||||
rm->pages = pages;
|
||||
}
|
||||
|
||||
return rm;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void omap_vram_free_region(struct vram_region *vr)
|
||||
{
|
||||
list_del(&vr->list);
|
||||
kfree(vr);
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct vram_alloc *omap_vram_create_allocation(struct vram_region *vr,
|
||||
unsigned long paddr, unsigned pages)
|
||||
{
|
||||
struct vram_alloc *va;
|
||||
struct vram_alloc *new;
|
||||
|
||||
new = kzalloc(sizeof(*va), GFP_KERNEL);
|
||||
|
||||
if (!new)
|
||||
return NULL;
|
||||
|
||||
new->paddr = paddr;
|
||||
new->pages = pages;
|
||||
|
||||
list_for_each_entry(va, &vr->alloc_list, list) {
|
||||
if (va->paddr > new->paddr)
|
||||
break;
|
||||
}
|
||||
|
||||
list_add_tail(&new->list, &va->list);
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
static void omap_vram_free_allocation(struct vram_alloc *va)
|
||||
{
|
||||
list_del(&va->list);
|
||||
kfree(va);
|
||||
}
|
||||
|
||||
int omap_vram_add_region(unsigned long paddr, size_t size)
|
||||
{
|
||||
struct vram_region *rm;
|
||||
unsigned pages;
|
||||
|
||||
if (vram_initialized) {
|
||||
DBG("adding region paddr %08lx size %d\n",
|
||||
paddr, size);
|
||||
|
||||
size &= PAGE_MASK;
|
||||
pages = size >> PAGE_SHIFT;
|
||||
|
||||
rm = omap_vram_create_region(paddr, pages);
|
||||
if (rm == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
list_add(&rm->list, ®ion_list);
|
||||
} else {
|
||||
if (postponed_cnt == MAX_POSTPONED_REGIONS)
|
||||
return -ENOMEM;
|
||||
|
||||
postponed_regions[postponed_cnt].paddr = paddr;
|
||||
postponed_regions[postponed_cnt].size = size;
|
||||
|
||||
++postponed_cnt;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int omap_vram_free(unsigned long paddr, size_t size)
|
||||
{
|
||||
struct vram_region *rm;
|
||||
struct vram_alloc *alloc;
|
||||
unsigned start, end;
|
||||
|
||||
DBG("free mem paddr %08lx size %d\n", paddr, size);
|
||||
|
||||
size = PAGE_ALIGN(size);
|
||||
|
||||
mutex_lock(®ion_mutex);
|
||||
|
||||
list_for_each_entry(rm, ®ion_list, list) {
|
||||
list_for_each_entry(alloc, &rm->alloc_list, list) {
|
||||
start = alloc->paddr;
|
||||
end = alloc->paddr + (alloc->pages >> PAGE_SHIFT);
|
||||
|
||||
if (start >= paddr && end < paddr + size)
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(®ion_mutex);
|
||||
return -EINVAL;
|
||||
|
||||
found:
|
||||
omap_vram_free_allocation(alloc);
|
||||
|
||||
mutex_unlock(®ion_mutex);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(omap_vram_free);
|
||||
|
||||
static int _omap_vram_reserve(unsigned long paddr, unsigned pages)
|
||||
{
|
||||
struct vram_region *rm;
|
||||
struct vram_alloc *alloc;
|
||||
size_t size;
|
||||
|
||||
size = pages << PAGE_SHIFT;
|
||||
|
||||
list_for_each_entry(rm, ®ion_list, list) {
|
||||
unsigned long start, end;
|
||||
|
||||
DBG("checking region %lx %d\n", rm->paddr, rm->pages);
|
||||
|
||||
if (region_mem_type(rm->paddr) != region_mem_type(paddr))
|
||||
continue;
|
||||
|
||||
start = rm->paddr;
|
||||
end = start + (rm->pages << PAGE_SHIFT) - 1;
|
||||
if (start > paddr || end < paddr + size - 1)
|
||||
continue;
|
||||
|
||||
DBG("block ok, checking allocs\n");
|
||||
|
||||
list_for_each_entry(alloc, &rm->alloc_list, list) {
|
||||
end = alloc->paddr - 1;
|
||||
|
||||
if (start <= paddr && end >= paddr + size - 1)
|
||||
goto found;
|
||||
|
||||
start = alloc->paddr + (alloc->pages << PAGE_SHIFT);
|
||||
}
|
||||
|
||||
end = rm->paddr + (rm->pages << PAGE_SHIFT) - 1;
|
||||
|
||||
if (!(start <= paddr && end >= paddr + size - 1))
|
||||
continue;
|
||||
found:
|
||||
DBG("found area start %lx, end %lx\n", start, end);
|
||||
|
||||
if (omap_vram_create_allocation(rm, paddr, pages) == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
int omap_vram_reserve(unsigned long paddr, size_t size)
|
||||
{
|
||||
unsigned pages;
|
||||
int r;
|
||||
|
||||
DBG("reserve mem paddr %08lx size %d\n", paddr, size);
|
||||
|
||||
size = PAGE_ALIGN(size);
|
||||
pages = size >> PAGE_SHIFT;
|
||||
|
||||
mutex_lock(®ion_mutex);
|
||||
|
||||
r = _omap_vram_reserve(paddr, pages);
|
||||
|
||||
mutex_unlock(®ion_mutex);
|
||||
|
||||
return r;
|
||||
}
|
||||
EXPORT_SYMBOL(omap_vram_reserve);
|
||||
|
||||
static void _omap_vram_dma_cb(int lch, u16 ch_status, void *data)
|
||||
{
|
||||
struct completion *compl = data;
|
||||
complete(compl);
|
||||
}
|
||||
|
||||
static int _omap_vram_clear(u32 paddr, unsigned pages)
|
||||
{
|
||||
struct completion compl;
|
||||
unsigned elem_count;
|
||||
unsigned frame_count;
|
||||
int r;
|
||||
int lch;
|
||||
|
||||
init_completion(&compl);
|
||||
|
||||
r = omap_request_dma(OMAP_DMA_NO_DEVICE, "VRAM DMA",
|
||||
_omap_vram_dma_cb,
|
||||
&compl, &lch);
|
||||
if (r) {
|
||||
pr_err("VRAM: request_dma failed for memory clear\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
elem_count = pages * PAGE_SIZE / 4;
|
||||
frame_count = 1;
|
||||
|
||||
omap_set_dma_transfer_params(lch, OMAP_DMA_DATA_TYPE_S32,
|
||||
elem_count, frame_count,
|
||||
OMAP_DMA_SYNC_ELEMENT,
|
||||
0, 0);
|
||||
|
||||
omap_set_dma_dest_params(lch, 0, OMAP_DMA_AMODE_POST_INC,
|
||||
paddr, 0, 0);
|
||||
|
||||
omap_set_dma_color_mode(lch, OMAP_DMA_CONSTANT_FILL, 0x000000);
|
||||
|
||||
omap_start_dma(lch);
|
||||
|
||||
if (wait_for_completion_timeout(&compl, msecs_to_jiffies(1000)) == 0) {
|
||||
omap_stop_dma(lch);
|
||||
pr_err("VRAM: dma timeout while clearing memory\n");
|
||||
r = -EIO;
|
||||
goto err;
|
||||
}
|
||||
|
||||
r = 0;
|
||||
err:
|
||||
omap_free_dma(lch);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _omap_vram_alloc(int mtype, unsigned pages, unsigned long *paddr)
|
||||
{
|
||||
struct vram_region *rm;
|
||||
struct vram_alloc *alloc;
|
||||
|
||||
list_for_each_entry(rm, ®ion_list, list) {
|
||||
unsigned long start, end;
|
||||
|
||||
DBG("checking region %lx %d\n", rm->paddr, rm->pages);
|
||||
|
||||
if (region_mem_type(rm->paddr) != mtype)
|
||||
continue;
|
||||
|
||||
start = rm->paddr;
|
||||
|
||||
list_for_each_entry(alloc, &rm->alloc_list, list) {
|
||||
end = alloc->paddr;
|
||||
|
||||
if (end - start >= pages << PAGE_SHIFT)
|
||||
goto found;
|
||||
|
||||
start = alloc->paddr + (alloc->pages << PAGE_SHIFT);
|
||||
}
|
||||
|
||||
end = rm->paddr + (rm->pages << PAGE_SHIFT);
|
||||
found:
|
||||
if (end - start < pages << PAGE_SHIFT)
|
||||
continue;
|
||||
|
||||
DBG("found %lx, end %lx\n", start, end);
|
||||
|
||||
alloc = omap_vram_create_allocation(rm, start, pages);
|
||||
if (alloc == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
*paddr = start;
|
||||
|
||||
_omap_vram_clear(start, pages);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
int omap_vram_alloc(int mtype, size_t size, unsigned long *paddr)
|
||||
{
|
||||
unsigned pages;
|
||||
int r;
|
||||
|
||||
BUG_ON(mtype > OMAP_VRAM_MEMTYPE_MAX || !size);
|
||||
|
||||
DBG("alloc mem type %d size %d\n", mtype, size);
|
||||
|
||||
size = PAGE_ALIGN(size);
|
||||
pages = size >> PAGE_SHIFT;
|
||||
|
||||
mutex_lock(®ion_mutex);
|
||||
|
||||
r = _omap_vram_alloc(mtype, pages, paddr);
|
||||
|
||||
mutex_unlock(®ion_mutex);
|
||||
|
||||
return r;
|
||||
}
|
||||
EXPORT_SYMBOL(omap_vram_alloc);
|
||||
|
||||
void omap_vram_get_info(unsigned long *vram,
|
||||
unsigned long *free_vram,
|
||||
unsigned long *largest_free_block)
|
||||
{
|
||||
struct vram_region *vr;
|
||||
struct vram_alloc *va;
|
||||
|
||||
*vram = 0;
|
||||
*free_vram = 0;
|
||||
*largest_free_block = 0;
|
||||
|
||||
mutex_lock(®ion_mutex);
|
||||
|
||||
list_for_each_entry(vr, ®ion_list, list) {
|
||||
unsigned free;
|
||||
unsigned long pa;
|
||||
|
||||
pa = vr->paddr;
|
||||
*vram += vr->pages << PAGE_SHIFT;
|
||||
|
||||
list_for_each_entry(va, &vr->alloc_list, list) {
|
||||
free = va->paddr - pa;
|
||||
*free_vram += free;
|
||||
if (free > *largest_free_block)
|
||||
*largest_free_block = free;
|
||||
pa = va->paddr + (va->pages << PAGE_SHIFT);
|
||||
}
|
||||
|
||||
free = vr->paddr + (vr->pages << PAGE_SHIFT) - pa;
|
||||
*free_vram += free;
|
||||
if (free > *largest_free_block)
|
||||
*largest_free_block = free;
|
||||
}
|
||||
|
||||
mutex_unlock(®ion_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(omap_vram_get_info);
|
||||
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
static int vram_debug_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct vram_region *vr;
|
||||
struct vram_alloc *va;
|
||||
unsigned size;
|
||||
|
||||
mutex_lock(®ion_mutex);
|
||||
|
||||
list_for_each_entry(vr, ®ion_list, list) {
|
||||
size = vr->pages << PAGE_SHIFT;
|
||||
seq_printf(s, "%08lx-%08lx (%d bytes)\n",
|
||||
vr->paddr, vr->paddr + size - 1,
|
||||
size);
|
||||
|
||||
list_for_each_entry(va, &vr->alloc_list, list) {
|
||||
size = va->pages << PAGE_SHIFT;
|
||||
seq_printf(s, " %08lx-%08lx (%d bytes)\n",
|
||||
va->paddr, va->paddr + size - 1,
|
||||
size);
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(®ion_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vram_debug_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, vram_debug_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations vram_debug_fops = {
|
||||
.open = vram_debug_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static int __init omap_vram_create_debugfs(void)
|
||||
{
|
||||
struct dentry *d;
|
||||
|
||||
d = debugfs_create_file("vram", S_IRUGO, NULL,
|
||||
NULL, &vram_debug_fops);
|
||||
if (IS_ERR(d))
|
||||
return PTR_ERR(d);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static __init int omap_vram_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
vram_initialized = 1;
|
||||
|
||||
for (i = 0; i < postponed_cnt; i++)
|
||||
omap_vram_add_region(postponed_regions[i].paddr,
|
||||
postponed_regions[i].size);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
if (omap_vram_create_debugfs())
|
||||
pr_err("VRAM: Failed to create debugfs file\n");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
arch_initcall(omap_vram_init);
|
||||
|
||||
/* boottime vram alloc stuff */
|
||||
|
||||
/* set from board file */
|
||||
static u32 omap_vram_sram_start __initdata;
|
||||
static u32 omap_vram_sram_size __initdata;
|
||||
|
||||
/* set from board file */
|
||||
static u32 omap_vram_sdram_start __initdata;
|
||||
static u32 omap_vram_sdram_size __initdata;
|
||||
|
||||
/* set from kernel cmdline */
|
||||
static u32 omap_vram_def_sdram_size __initdata;
|
||||
static u32 omap_vram_def_sdram_start __initdata;
|
||||
|
||||
static void __init omap_vram_early_vram(char **p)
|
||||
{
|
||||
omap_vram_def_sdram_size = memparse(*p, p);
|
||||
if (**p == ',')
|
||||
omap_vram_def_sdram_start = simple_strtoul((*p) + 1, p, 16);
|
||||
}
|
||||
__early_param("vram=", omap_vram_early_vram);
|
||||
|
||||
/*
|
||||
* Called from map_io. We need to call to this early enough so that we
|
||||
* can reserve the fixed SDRAM regions before VM could get hold of them.
|
||||
*/
|
||||
void __init omap_vram_reserve_sdram(void)
|
||||
{
|
||||
struct bootmem_data *bdata;
|
||||
unsigned long sdram_start, sdram_size;
|
||||
u32 paddr;
|
||||
u32 size = 0;
|
||||
|
||||
/* cmdline arg overrides the board file definition */
|
||||
if (omap_vram_def_sdram_size) {
|
||||
size = omap_vram_def_sdram_size;
|
||||
paddr = omap_vram_def_sdram_start;
|
||||
}
|
||||
|
||||
if (!size) {
|
||||
size = omap_vram_sdram_size;
|
||||
paddr = omap_vram_sdram_start;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OMAP2_VRAM_SIZE
|
||||
if (!size) {
|
||||
size = CONFIG_OMAP2_VRAM_SIZE * 1024 * 1024;
|
||||
paddr = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!size)
|
||||
return;
|
||||
|
||||
size = PAGE_ALIGN(size);
|
||||
|
||||
bdata = NODE_DATA(0)->bdata;
|
||||
sdram_start = bdata->node_min_pfn << PAGE_SHIFT;
|
||||
sdram_size = (bdata->node_low_pfn << PAGE_SHIFT) - sdram_start;
|
||||
|
||||
if (paddr) {
|
||||
if ((paddr & ~PAGE_MASK) || paddr < sdram_start ||
|
||||
paddr + size > sdram_start + sdram_size) {
|
||||
pr_err("Illegal SDRAM region for VRAM\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (reserve_bootmem(paddr, size, BOOTMEM_EXCLUSIVE) < 0) {
|
||||
pr_err("FB: failed to reserve VRAM\n");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (size > sdram_size) {
|
||||
pr_err("Illegal SDRAM size for VRAM\n");
|
||||
return;
|
||||
}
|
||||
|
||||
paddr = virt_to_phys(alloc_bootmem_pages(size));
|
||||
BUG_ON(paddr & ~PAGE_MASK);
|
||||
}
|
||||
|
||||
omap_vram_add_region(paddr, size);
|
||||
|
||||
pr_info("Reserving %u bytes SDRAM for VRAM\n", size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called at sram init time, before anything is pushed to the SRAM stack.
|
||||
* Because of the stack scheme, we will allocate everything from the
|
||||
* start of the lowest address region to the end of SRAM. This will also
|
||||
* include padding for page alignment and possible holes between regions.
|
||||
*
|
||||
* As opposed to the SDRAM case, we'll also do any dynamic allocations at
|
||||
* this point, since the driver built as a module would have problem with
|
||||
* freeing / reallocating the regions.
|
||||
*/
|
||||
unsigned long __init omap_vram_reserve_sram(unsigned long sram_pstart,
|
||||
unsigned long sram_vstart,
|
||||
unsigned long sram_size,
|
||||
unsigned long pstart_avail,
|
||||
unsigned long size_avail)
|
||||
{
|
||||
unsigned long pend_avail;
|
||||
unsigned long reserved;
|
||||
u32 paddr;
|
||||
u32 size;
|
||||
|
||||
paddr = omap_vram_sram_start;
|
||||
size = omap_vram_sram_size;
|
||||
|
||||
if (!size)
|
||||
return 0;
|
||||
|
||||
reserved = 0;
|
||||
pend_avail = pstart_avail + size_avail;
|
||||
|
||||
if (!paddr) {
|
||||
/* Dynamic allocation */
|
||||
if ((size_avail & PAGE_MASK) < size) {
|
||||
pr_err("Not enough SRAM for VRAM\n");
|
||||
return 0;
|
||||
}
|
||||
size_avail = (size_avail - size) & PAGE_MASK;
|
||||
paddr = pstart_avail + size_avail;
|
||||
}
|
||||
|
||||
if (paddr < sram_pstart ||
|
||||
paddr + size > sram_pstart + sram_size) {
|
||||
pr_err("Illegal SRAM region for VRAM\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Reserve everything above the start of the region. */
|
||||
if (pend_avail - paddr > reserved)
|
||||
reserved = pend_avail - paddr;
|
||||
size_avail = pend_avail - reserved - pstart_avail;
|
||||
|
||||
omap_vram_add_region(paddr, size);
|
||||
|
||||
if (reserved)
|
||||
pr_info("Reserving %lu bytes SRAM for VRAM\n", reserved);
|
||||
|
||||
return reserved;
|
||||
}
|
||||
|
||||
void __init omap_vram_set_sdram_vram(u32 size, u32 start)
|
||||
{
|
||||
omap_vram_sdram_start = start;
|
||||
omap_vram_sdram_size = size;
|
||||
}
|
||||
|
||||
void __init omap_vram_set_sram_vram(u32 size, u32 start)
|
||||
{
|
||||
omap_vram_sram_start = start;
|
||||
omap_vram_sram_size = size;
|
||||
}
|
315
drivers/video/omap2/vrfb.c
Normal file
315
drivers/video/omap2/vrfb.c
Normal file
@ -0,0 +1,315 @@
|
||||
/*
|
||||
* VRFB Rotation Engine
|
||||
*
|
||||
* Copyright (C) 2009 Nokia Corporation
|
||||
* Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/*#define DEBUG*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include <mach/io.h>
|
||||
#include <plat/vrfb.h>
|
||||
#include <plat/sdrc.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DBG(format, ...) pr_debug("VRFB: " format, ## __VA_ARGS__)
|
||||
#else
|
||||
#define DBG(format, ...)
|
||||
#endif
|
||||
|
||||
#define SMS_ROT_VIRT_BASE(context, rot) \
|
||||
(((context >= 4) ? 0xD0000000 : 0x70000000) \
|
||||
+ (0x4000000 * (context)) \
|
||||
+ (0x1000000 * (rot)))
|
||||
|
||||
#define OMAP_VRFB_SIZE (2048 * 2048 * 4)
|
||||
|
||||
#define VRFB_PAGE_WIDTH_EXP 5 /* Assuming SDRAM pagesize= 1024 */
|
||||
#define VRFB_PAGE_HEIGHT_EXP 5 /* 1024 = 2^5 * 2^5 */
|
||||
#define VRFB_PAGE_WIDTH (1 << VRFB_PAGE_WIDTH_EXP)
|
||||
#define VRFB_PAGE_HEIGHT (1 << VRFB_PAGE_HEIGHT_EXP)
|
||||
#define SMS_IMAGEHEIGHT_OFFSET 16
|
||||
#define SMS_IMAGEWIDTH_OFFSET 0
|
||||
#define SMS_PH_OFFSET 8
|
||||
#define SMS_PW_OFFSET 4
|
||||
#define SMS_PS_OFFSET 0
|
||||
|
||||
#define VRFB_NUM_CTXS 12
|
||||
/* bitmap of reserved contexts */
|
||||
static unsigned long ctx_map;
|
||||
|
||||
static DEFINE_MUTEX(ctx_lock);
|
||||
|
||||
/*
|
||||
* Access to this happens from client drivers or the PM core after wake-up.
|
||||
* For the first case we require locking at the driver level, for the second
|
||||
* we don't need locking, since no drivers will run until after the wake-up
|
||||
* has finished.
|
||||
*/
|
||||
static struct {
|
||||
u32 physical_ba;
|
||||
u32 control;
|
||||
u32 size;
|
||||
} vrfb_hw_context[VRFB_NUM_CTXS];
|
||||
|
||||
static inline void restore_hw_context(int ctx)
|
||||
{
|
||||
omap2_sms_write_rot_control(vrfb_hw_context[ctx].control, ctx);
|
||||
omap2_sms_write_rot_size(vrfb_hw_context[ctx].size, ctx);
|
||||
omap2_sms_write_rot_physical_ba(vrfb_hw_context[ctx].physical_ba, ctx);
|
||||
}
|
||||
|
||||
static u32 get_image_width_roundup(u16 width, u8 bytespp)
|
||||
{
|
||||
unsigned long stride = width * bytespp;
|
||||
unsigned long ceil_pages_per_stride = (stride / VRFB_PAGE_WIDTH) +
|
||||
(stride % VRFB_PAGE_WIDTH != 0);
|
||||
|
||||
return ceil_pages_per_stride * VRFB_PAGE_WIDTH / bytespp;
|
||||
}
|
||||
|
||||
/*
|
||||
* This the extra space needed in the VRFB physical area for VRFB to safely wrap
|
||||
* any memory accesses to the invisible part of the virtual view to the physical
|
||||
* area.
|
||||
*/
|
||||
static inline u32 get_extra_physical_size(u16 image_width_roundup, u8 bytespp)
|
||||
{
|
||||
return (OMAP_VRFB_LINE_LEN - image_width_roundup) * VRFB_PAGE_HEIGHT *
|
||||
bytespp;
|
||||
}
|
||||
|
||||
void omap_vrfb_restore_context(void)
|
||||
{
|
||||
int i;
|
||||
unsigned long map = ctx_map;
|
||||
|
||||
for (i = ffs(map); i; i = ffs(map)) {
|
||||
/* i=1..32 */
|
||||
i--;
|
||||
map &= ~(1 << i);
|
||||
restore_hw_context(i);
|
||||
}
|
||||
}
|
||||
|
||||
void omap_vrfb_adjust_size(u16 *width, u16 *height,
|
||||
u8 bytespp)
|
||||
{
|
||||
*width = ALIGN(*width * bytespp, VRFB_PAGE_WIDTH) / bytespp;
|
||||
*height = ALIGN(*height, VRFB_PAGE_HEIGHT);
|
||||
}
|
||||
EXPORT_SYMBOL(omap_vrfb_adjust_size);
|
||||
|
||||
u32 omap_vrfb_min_phys_size(u16 width, u16 height, u8 bytespp)
|
||||
{
|
||||
unsigned long image_width_roundup = get_image_width_roundup(width,
|
||||
bytespp);
|
||||
|
||||
if (image_width_roundup > OMAP_VRFB_LINE_LEN)
|
||||
return 0;
|
||||
|
||||
return (width * height * bytespp) + get_extra_physical_size(
|
||||
image_width_roundup, bytespp);
|
||||
}
|
||||
EXPORT_SYMBOL(omap_vrfb_min_phys_size);
|
||||
|
||||
u16 omap_vrfb_max_height(u32 phys_size, u16 width, u8 bytespp)
|
||||
{
|
||||
unsigned long image_width_roundup = get_image_width_roundup(width,
|
||||
bytespp);
|
||||
unsigned long height;
|
||||
unsigned long extra;
|
||||
|
||||
if (image_width_roundup > OMAP_VRFB_LINE_LEN)
|
||||
return 0;
|
||||
|
||||
extra = get_extra_physical_size(image_width_roundup, bytespp);
|
||||
|
||||
if (phys_size < extra)
|
||||
return 0;
|
||||
|
||||
height = (phys_size - extra) / (width * bytespp);
|
||||
|
||||
/* Virtual views provided by VRFB are limited to 2048x2048. */
|
||||
return min_t(unsigned long, height, 2048);
|
||||
}
|
||||
EXPORT_SYMBOL(omap_vrfb_max_height);
|
||||
|
||||
void omap_vrfb_setup(struct vrfb *vrfb, unsigned long paddr,
|
||||
u16 width, u16 height,
|
||||
unsigned bytespp, bool yuv_mode)
|
||||
{
|
||||
unsigned pixel_size_exp;
|
||||
u16 vrfb_width;
|
||||
u16 vrfb_height;
|
||||
u8 ctx = vrfb->context;
|
||||
u32 size;
|
||||
u32 control;
|
||||
|
||||
DBG("omapfb_set_vrfb(%d, %lx, %dx%d, %d, %d)\n", ctx, paddr,
|
||||
width, height, bytespp, yuv_mode);
|
||||
|
||||
/* For YUV2 and UYVY modes VRFB needs to handle pixels a bit
|
||||
* differently. See TRM. */
|
||||
if (yuv_mode) {
|
||||
bytespp *= 2;
|
||||
width /= 2;
|
||||
}
|
||||
|
||||
if (bytespp == 4)
|
||||
pixel_size_exp = 2;
|
||||
else if (bytespp == 2)
|
||||
pixel_size_exp = 1;
|
||||
else
|
||||
BUG();
|
||||
|
||||
vrfb_width = ALIGN(width * bytespp, VRFB_PAGE_WIDTH) / bytespp;
|
||||
vrfb_height = ALIGN(height, VRFB_PAGE_HEIGHT);
|
||||
|
||||
DBG("vrfb w %u, h %u bytespp %d\n", vrfb_width, vrfb_height, bytespp);
|
||||
|
||||
size = vrfb_width << SMS_IMAGEWIDTH_OFFSET;
|
||||
size |= vrfb_height << SMS_IMAGEHEIGHT_OFFSET;
|
||||
|
||||
control = pixel_size_exp << SMS_PS_OFFSET;
|
||||
control |= VRFB_PAGE_WIDTH_EXP << SMS_PW_OFFSET;
|
||||
control |= VRFB_PAGE_HEIGHT_EXP << SMS_PH_OFFSET;
|
||||
|
||||
vrfb_hw_context[ctx].physical_ba = paddr;
|
||||
vrfb_hw_context[ctx].size = size;
|
||||
vrfb_hw_context[ctx].control = control;
|
||||
|
||||
omap2_sms_write_rot_physical_ba(paddr, ctx);
|
||||
omap2_sms_write_rot_size(size, ctx);
|
||||
omap2_sms_write_rot_control(control, ctx);
|
||||
|
||||
DBG("vrfb offset pixels %d, %d\n",
|
||||
vrfb_width - width, vrfb_height - height);
|
||||
|
||||
vrfb->xres = width;
|
||||
vrfb->yres = height;
|
||||
vrfb->xoffset = vrfb_width - width;
|
||||
vrfb->yoffset = vrfb_height - height;
|
||||
vrfb->bytespp = bytespp;
|
||||
vrfb->yuv_mode = yuv_mode;
|
||||
}
|
||||
EXPORT_SYMBOL(omap_vrfb_setup);
|
||||
|
||||
int omap_vrfb_map_angle(struct vrfb *vrfb, u16 height, u8 rot)
|
||||
{
|
||||
unsigned long size = height * OMAP_VRFB_LINE_LEN * vrfb->bytespp;
|
||||
|
||||
vrfb->vaddr[rot] = ioremap_wc(vrfb->paddr[rot], size);
|
||||
|
||||
if (!vrfb->vaddr[rot]) {
|
||||
printk(KERN_ERR "vrfb: ioremap failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
DBG("ioremapped vrfb area %d of size %lu into %p\n", rot, size,
|
||||
vrfb->vaddr[rot]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(omap_vrfb_map_angle);
|
||||
|
||||
void omap_vrfb_release_ctx(struct vrfb *vrfb)
|
||||
{
|
||||
int rot;
|
||||
int ctx = vrfb->context;
|
||||
|
||||
if (ctx == 0xff)
|
||||
return;
|
||||
|
||||
DBG("release ctx %d\n", ctx);
|
||||
|
||||
mutex_lock(&ctx_lock);
|
||||
|
||||
BUG_ON(!(ctx_map & (1 << ctx)));
|
||||
|
||||
clear_bit(ctx, &ctx_map);
|
||||
|
||||
for (rot = 0; rot < 4; ++rot) {
|
||||
if (vrfb->paddr[rot]) {
|
||||
release_mem_region(vrfb->paddr[rot], OMAP_VRFB_SIZE);
|
||||
vrfb->paddr[rot] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
vrfb->context = 0xff;
|
||||
|
||||
mutex_unlock(&ctx_lock);
|
||||
}
|
||||
EXPORT_SYMBOL(omap_vrfb_release_ctx);
|
||||
|
||||
int omap_vrfb_request_ctx(struct vrfb *vrfb)
|
||||
{
|
||||
int rot;
|
||||
u32 paddr;
|
||||
u8 ctx;
|
||||
int r;
|
||||
|
||||
DBG("request ctx\n");
|
||||
|
||||
mutex_lock(&ctx_lock);
|
||||
|
||||
for (ctx = 0; ctx < VRFB_NUM_CTXS; ++ctx)
|
||||
if ((ctx_map & (1 << ctx)) == 0)
|
||||
break;
|
||||
|
||||
if (ctx == VRFB_NUM_CTXS) {
|
||||
pr_err("vrfb: no free contexts\n");
|
||||
r = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
DBG("found free ctx %d\n", ctx);
|
||||
|
||||
set_bit(ctx, &ctx_map);
|
||||
|
||||
memset(vrfb, 0, sizeof(*vrfb));
|
||||
|
||||
vrfb->context = ctx;
|
||||
|
||||
for (rot = 0; rot < 4; ++rot) {
|
||||
paddr = SMS_ROT_VIRT_BASE(ctx, rot);
|
||||
if (!request_mem_region(paddr, OMAP_VRFB_SIZE, "vrfb")) {
|
||||
pr_err("vrfb: failed to reserve VRFB "
|
||||
"area for ctx %d, rotation %d\n",
|
||||
ctx, rot * 90);
|
||||
omap_vrfb_release_ctx(vrfb);
|
||||
r = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
vrfb->paddr[rot] = paddr;
|
||||
|
||||
DBG("VRFB %d/%d: %lx\n", ctx, rot*90, vrfb->paddr[rot]);
|
||||
}
|
||||
|
||||
r = 0;
|
||||
out:
|
||||
mutex_unlock(&ctx_lock);
|
||||
return r;
|
||||
}
|
||||
EXPORT_SYMBOL(omap_vrfb_request_ctx);
|
251
include/linux/omapfb.h
Normal file
251
include/linux/omapfb.h
Normal file
@ -0,0 +1,251 @@
|
||||
/*
|
||||
* File: include/linux/omapfb.h
|
||||
*
|
||||
* Framebuffer driver for TI OMAP boards
|
||||
*
|
||||
* Copyright (C) 2004 Nokia Corporation
|
||||
* Author: Imre Deak <imre.deak@nokia.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_OMAPFB_H__
|
||||
#define __LINUX_OMAPFB_H__
|
||||
|
||||
#include <linux/fb.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
/* IOCTL commands. */
|
||||
|
||||
#define OMAP_IOW(num, dtype) _IOW('O', num, dtype)
|
||||
#define OMAP_IOR(num, dtype) _IOR('O', num, dtype)
|
||||
#define OMAP_IOWR(num, dtype) _IOWR('O', num, dtype)
|
||||
#define OMAP_IO(num) _IO('O', num)
|
||||
|
||||
#define OMAPFB_MIRROR OMAP_IOW(31, int)
|
||||
#define OMAPFB_SYNC_GFX OMAP_IO(37)
|
||||
#define OMAPFB_VSYNC OMAP_IO(38)
|
||||
#define OMAPFB_SET_UPDATE_MODE OMAP_IOW(40, int)
|
||||
#define OMAPFB_GET_CAPS OMAP_IOR(42, struct omapfb_caps)
|
||||
#define OMAPFB_GET_UPDATE_MODE OMAP_IOW(43, int)
|
||||
#define OMAPFB_LCD_TEST OMAP_IOW(45, int)
|
||||
#define OMAPFB_CTRL_TEST OMAP_IOW(46, int)
|
||||
#define OMAPFB_UPDATE_WINDOW_OLD OMAP_IOW(47, struct omapfb_update_window_old)
|
||||
#define OMAPFB_SET_COLOR_KEY OMAP_IOW(50, struct omapfb_color_key)
|
||||
#define OMAPFB_GET_COLOR_KEY OMAP_IOW(51, struct omapfb_color_key)
|
||||
#define OMAPFB_SETUP_PLANE OMAP_IOW(52, struct omapfb_plane_info)
|
||||
#define OMAPFB_QUERY_PLANE OMAP_IOW(53, struct omapfb_plane_info)
|
||||
#define OMAPFB_UPDATE_WINDOW OMAP_IOW(54, struct omapfb_update_window)
|
||||
#define OMAPFB_SETUP_MEM OMAP_IOW(55, struct omapfb_mem_info)
|
||||
#define OMAPFB_QUERY_MEM OMAP_IOW(56, struct omapfb_mem_info)
|
||||
#define OMAPFB_WAITFORVSYNC OMAP_IO(57)
|
||||
#define OMAPFB_MEMORY_READ OMAP_IOR(58, struct omapfb_memory_read)
|
||||
#define OMAPFB_GET_OVERLAY_COLORMODE OMAP_IOR(59, struct omapfb_ovl_colormode)
|
||||
#define OMAPFB_WAITFORGO OMAP_IO(60)
|
||||
#define OMAPFB_GET_VRAM_INFO OMAP_IOR(61, struct omapfb_vram_info)
|
||||
#define OMAPFB_SET_TEARSYNC OMAP_IOW(62, struct omapfb_tearsync_info)
|
||||
|
||||
#define OMAPFB_CAPS_GENERIC_MASK 0x00000fff
|
||||
#define OMAPFB_CAPS_LCDC_MASK 0x00fff000
|
||||
#define OMAPFB_CAPS_PANEL_MASK 0xff000000
|
||||
|
||||
#define OMAPFB_CAPS_MANUAL_UPDATE 0x00001000
|
||||
#define OMAPFB_CAPS_TEARSYNC 0x00002000
|
||||
#define OMAPFB_CAPS_PLANE_RELOCATE_MEM 0x00004000
|
||||
#define OMAPFB_CAPS_PLANE_SCALE 0x00008000
|
||||
#define OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE 0x00010000
|
||||
#define OMAPFB_CAPS_WINDOW_SCALE 0x00020000
|
||||
#define OMAPFB_CAPS_WINDOW_OVERLAY 0x00040000
|
||||
#define OMAPFB_CAPS_WINDOW_ROTATE 0x00080000
|
||||
#define OMAPFB_CAPS_SET_BACKLIGHT 0x01000000
|
||||
|
||||
/* Values from DSP must map to lower 16-bits */
|
||||
#define OMAPFB_FORMAT_MASK 0x00ff
|
||||
#define OMAPFB_FORMAT_FLAG_DOUBLE 0x0100
|
||||
#define OMAPFB_FORMAT_FLAG_TEARSYNC 0x0200
|
||||
#define OMAPFB_FORMAT_FLAG_FORCE_VSYNC 0x0400
|
||||
#define OMAPFB_FORMAT_FLAG_ENABLE_OVERLAY 0x0800
|
||||
#define OMAPFB_FORMAT_FLAG_DISABLE_OVERLAY 0x1000
|
||||
|
||||
#define OMAPFB_MEMTYPE_SDRAM 0
|
||||
#define OMAPFB_MEMTYPE_SRAM 1
|
||||
#define OMAPFB_MEMTYPE_MAX 1
|
||||
|
||||
enum omapfb_color_format {
|
||||
OMAPFB_COLOR_RGB565 = 0,
|
||||
OMAPFB_COLOR_YUV422,
|
||||
OMAPFB_COLOR_YUV420,
|
||||
OMAPFB_COLOR_CLUT_8BPP,
|
||||
OMAPFB_COLOR_CLUT_4BPP,
|
||||
OMAPFB_COLOR_CLUT_2BPP,
|
||||
OMAPFB_COLOR_CLUT_1BPP,
|
||||
OMAPFB_COLOR_RGB444,
|
||||
OMAPFB_COLOR_YUY422,
|
||||
|
||||
OMAPFB_COLOR_ARGB16,
|
||||
OMAPFB_COLOR_RGB24U, /* RGB24, 32-bit container */
|
||||
OMAPFB_COLOR_RGB24P, /* RGB24, 24-bit container */
|
||||
OMAPFB_COLOR_ARGB32,
|
||||
OMAPFB_COLOR_RGBA32,
|
||||
OMAPFB_COLOR_RGBX32,
|
||||
};
|
||||
|
||||
struct omapfb_update_window {
|
||||
__u32 x, y;
|
||||
__u32 width, height;
|
||||
__u32 format;
|
||||
__u32 out_x, out_y;
|
||||
__u32 out_width, out_height;
|
||||
__u32 reserved[8];
|
||||
};
|
||||
|
||||
struct omapfb_update_window_old {
|
||||
__u32 x, y;
|
||||
__u32 width, height;
|
||||
__u32 format;
|
||||
};
|
||||
|
||||
enum omapfb_plane {
|
||||
OMAPFB_PLANE_GFX = 0,
|
||||
OMAPFB_PLANE_VID1,
|
||||
OMAPFB_PLANE_VID2,
|
||||
};
|
||||
|
||||
enum omapfb_channel_out {
|
||||
OMAPFB_CHANNEL_OUT_LCD = 0,
|
||||
OMAPFB_CHANNEL_OUT_DIGIT,
|
||||
};
|
||||
|
||||
struct omapfb_plane_info {
|
||||
__u32 pos_x;
|
||||
__u32 pos_y;
|
||||
__u8 enabled;
|
||||
__u8 channel_out;
|
||||
__u8 mirror;
|
||||
__u8 reserved1;
|
||||
__u32 out_width;
|
||||
__u32 out_height;
|
||||
__u32 reserved2[12];
|
||||
};
|
||||
|
||||
struct omapfb_mem_info {
|
||||
__u32 size;
|
||||
__u8 type;
|
||||
__u8 reserved[3];
|
||||
};
|
||||
|
||||
struct omapfb_caps {
|
||||
__u32 ctrl;
|
||||
__u32 plane_color;
|
||||
__u32 wnd_color;
|
||||
};
|
||||
|
||||
enum omapfb_color_key_type {
|
||||
OMAPFB_COLOR_KEY_DISABLED = 0,
|
||||
OMAPFB_COLOR_KEY_GFX_DST,
|
||||
OMAPFB_COLOR_KEY_VID_SRC,
|
||||
};
|
||||
|
||||
struct omapfb_color_key {
|
||||
__u8 channel_out;
|
||||
__u32 background;
|
||||
__u32 trans_key;
|
||||
__u8 key_type;
|
||||
};
|
||||
|
||||
enum omapfb_update_mode {
|
||||
OMAPFB_UPDATE_DISABLED = 0,
|
||||
OMAPFB_AUTO_UPDATE,
|
||||
OMAPFB_MANUAL_UPDATE
|
||||
};
|
||||
|
||||
struct omapfb_memory_read {
|
||||
__u16 x;
|
||||
__u16 y;
|
||||
__u16 w;
|
||||
__u16 h;
|
||||
size_t buffer_size;
|
||||
void __user *buffer;
|
||||
};
|
||||
|
||||
struct omapfb_ovl_colormode {
|
||||
__u8 overlay_idx;
|
||||
__u8 mode_idx;
|
||||
__u32 bits_per_pixel;
|
||||
__u32 nonstd;
|
||||
struct fb_bitfield red;
|
||||
struct fb_bitfield green;
|
||||
struct fb_bitfield blue;
|
||||
struct fb_bitfield transp;
|
||||
};
|
||||
|
||||
struct omapfb_vram_info {
|
||||
__u32 total;
|
||||
__u32 free;
|
||||
__u32 largest_free_block;
|
||||
__u32 reserved[5];
|
||||
};
|
||||
|
||||
struct omapfb_tearsync_info {
|
||||
__u8 enabled;
|
||||
__u8 reserved1[3];
|
||||
__u16 line;
|
||||
__u16 reserved2;
|
||||
};
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#include <plat/board.h>
|
||||
|
||||
#ifdef CONFIG_ARCH_OMAP1
|
||||
#define OMAPFB_PLANE_NUM 1
|
||||
#else
|
||||
#define OMAPFB_PLANE_NUM 3
|
||||
#endif
|
||||
|
||||
struct omapfb_mem_region {
|
||||
u32 paddr;
|
||||
void __iomem *vaddr;
|
||||
unsigned long size;
|
||||
u8 type; /* OMAPFB_PLANE_MEM_* */
|
||||
enum omapfb_color_format format;/* OMAPFB_COLOR_* */
|
||||
unsigned format_used:1; /* Must be set when format is set.
|
||||
* Needed b/c of the badly chosen 0
|
||||
* base for OMAPFB_COLOR_* values
|
||||
*/
|
||||
unsigned alloc:1; /* allocated by the driver */
|
||||
unsigned map:1; /* kernel mapped by the driver */
|
||||
};
|
||||
|
||||
struct omapfb_mem_desc {
|
||||
int region_cnt;
|
||||
struct omapfb_mem_region region[OMAPFB_PLANE_NUM];
|
||||
};
|
||||
|
||||
struct omapfb_platform_data {
|
||||
struct omap_lcd_config lcd;
|
||||
struct omapfb_mem_desc mem_desc;
|
||||
void *ctrl_platform_data;
|
||||
};
|
||||
|
||||
/* in arch/arm/plat-omap/fb.c */
|
||||
extern void omapfb_set_platform_data(struct omapfb_platform_data *data);
|
||||
extern void omapfb_set_ctrl_platform_data(void *pdata);
|
||||
extern void omapfb_reserve_sdram(void);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* __OMAPFB_H */
|
Loading…
Reference in New Issue
Block a user