1
0
Fork 0

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
wifi-calibration
Linus Torvalds 2009-12-10 21:55:17 -08:00
commit aa2cf42059
74 changed files with 21994 additions and 250 deletions

View 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

View File

@ -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

View File

@ -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
#

View File

@ -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>

View File

@ -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);
}

View File

@ -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),

View File

@ -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),

View File

@ -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();
}
/*

View File

@ -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));
}

View File

@ -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

View 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

View File

@ -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 {

View 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

View 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 */

View File

@ -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;
}

View File

@ -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"

View File

@ -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/

View File

@ -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

View File

@ -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"

View File

@ -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 = {

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -26,7 +26,8 @@
#include <mach/gpio.h>
#include <plat/mux.h>
#include <plat/omapfb.h>
#include "omapfb.h"
/* #define USE_35INCH_LCD 1 */

View File

@ -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"

View File

@ -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)
{

View File

@ -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)

View File

@ -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)

View File

@ -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"

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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)
{

View File

@ -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,

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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"

View File

@ -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 */

View File

@ -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"

View File

@ -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 */

View File

@ -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"

View 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"

View 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/

View 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

View 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

View 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");

View 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");

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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");

File diff suppressed because it is too large Load Diff

View 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);

View 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)
{
}

File diff suppressed because it is too large Load Diff

View 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);
}

View 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

File diff suppressed because it is too large Load Diff

View 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;
}

File diff suppressed because it is too large Load Diff

View 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)
{
}

View 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
}

View 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.

View File

@ -0,0 +1,2 @@
obj-$(CONFIG_FB_OMAP2) += omapfb.o
omapfb-y := omapfb-main.o omapfb-sysfs.o omapfb-ioctl.o

View 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;
}

File diff suppressed because it is too large Load Diff

View 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]);
}
}

View 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

View 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, &region_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(&region_mutex);
list_for_each_entry(rm, &region_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(&region_mutex);
return -EINVAL;
found:
omap_vram_free_allocation(alloc);
mutex_unlock(&region_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, &region_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(&region_mutex);
r = _omap_vram_reserve(paddr, pages);
mutex_unlock(&region_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, &region_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(&region_mutex);
r = _omap_vram_alloc(mtype, pages, paddr);
mutex_unlock(&region_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(&region_mutex);
list_for_each_entry(vr, &region_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(&region_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(&region_mutex);
list_for_each_entry(vr, &region_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(&region_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;
}

View 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);

View 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 */