diff options
Diffstat (limited to 'packages/linux/linux-omap-2.6.28/0001-DSS-New-display-subsystem-driver-for-OMAP2-3.patch')
-rw-r--r-- | packages/linux/linux-omap-2.6.28/0001-DSS-New-display-subsystem-driver-for-OMAP2-3.patch | 10365 |
1 files changed, 0 insertions, 10365 deletions
diff --git a/packages/linux/linux-omap-2.6.28/0001-DSS-New-display-subsystem-driver-for-OMAP2-3.patch b/packages/linux/linux-omap-2.6.28/0001-DSS-New-display-subsystem-driver-for-OMAP2-3.patch deleted file mode 100644 index fda5191421..0000000000 --- a/packages/linux/linux-omap-2.6.28/0001-DSS-New-display-subsystem-driver-for-OMAP2-3.patch +++ /dev/null @@ -1,10365 +0,0 @@ -From 3128e95ff7e6a1bed47cc5c64a138cc3bbab492a Mon Sep 17 00:00:00 2001 -From: Tomi Valkeinen <tomi.valkeinen@nokia.com> -Date: Wed, 7 Jan 2009 14:30:09 +0200 -Subject: [PATCH] DSS: New display subsystem driver for OMAP2/3 - -Signed-off-by: Tomi Valkeinen <tomi.valkeinen@nokia.com> ---- - Documentation/arm/OMAP/DSS | 266 +++ - arch/arm/plat-omap/Kconfig | 2 + - arch/arm/plat-omap/Makefile | 2 + - arch/arm/plat-omap/dss/Kconfig | 69 + - arch/arm/plat-omap/dss/Makefile | 6 + - arch/arm/plat-omap/dss/dispc.c | 2113 +++++++++++++++++++ - arch/arm/plat-omap/dss/display.c | 787 +++++++ - arch/arm/plat-omap/dss/dpi.c | 344 ++++ - arch/arm/plat-omap/dss/dsi.c | 3187 +++++++++++++++++++++++++++++ - arch/arm/plat-omap/dss/dss.c | 774 +++++++ - arch/arm/plat-omap/dss/dss.h | 274 +++ - arch/arm/plat-omap/dss/rfbi.c | 1262 ++++++++++++ - arch/arm/plat-omap/dss/sdi.c | 174 ++ - arch/arm/plat-omap/dss/venc.c | 506 +++++ - arch/arm/plat-omap/include/mach/display.h | 462 +++++ - 15 files changed, 10228 insertions(+), 0 deletions(-) - create mode 100644 Documentation/arm/OMAP/DSS - create mode 100644 arch/arm/plat-omap/dss/Kconfig - create mode 100644 arch/arm/plat-omap/dss/Makefile - create mode 100644 arch/arm/plat-omap/dss/dispc.c - create mode 100644 arch/arm/plat-omap/dss/display.c - create mode 100644 arch/arm/plat-omap/dss/dpi.c - create mode 100644 arch/arm/plat-omap/dss/dsi.c - create mode 100644 arch/arm/plat-omap/dss/dss.c - create mode 100644 arch/arm/plat-omap/dss/dss.h - create mode 100644 arch/arm/plat-omap/dss/rfbi.c - create mode 100644 arch/arm/plat-omap/dss/sdi.c - create mode 100644 arch/arm/plat-omap/dss/venc.c - create mode 100644 arch/arm/plat-omap/include/mach/display.h - -diff --git a/Documentation/arm/OMAP/DSS b/Documentation/arm/OMAP/DSS -new file mode 100644 -index 0000000..a5e608c ---- /dev/null -+++ b/Documentation/arm/OMAP/DSS -@@ -0,0 +1,266 @@ -+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. -+ -+The DSS2 driver (omap-dss 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 (not tested for a while, might've gotten broken) -+- 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 -+ -+omap-dss 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, omap-dss 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 -+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 -+------------ -+ -+Currently there are no V4L2 display drivers planned, but it is possible to -+implement such either to omapfb driver, or as a separate one. From omap-dss -+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 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 a hack, but works 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. -+ -+In /sys/devices/platform/omapfb we have four files: framebuffers, -+overlays, managers and displays. You can read them so see the current -+setup, and change them by writing to it in the form of -+"<item-id> <opt1>:<val1> <opt2>:<val2>..." -+ -+"framebuffers" lists all framebuffers. Its format is: -+ <fb number> -+ p:<physical address, read only> -+ v:<virtual address, read only> -+ s:<size, read only> -+ t:<target overlay> -+ -+"overlays" lists all overlays. Its format is: -+ <overlay name> -+ t:<target manager> -+ x:<xpos> -+ y:<ypos> -+ iw:<input width, read only> -+ ih:<input height, read only> -+ w:<output width> -+ h:<output height> -+ e:<enabled> -+ -+"managers" lists all overlay managers. Its format is: -+ <manager name> -+ t:<target display> -+ -+"displays" lists all displays. Its format is: -+ <display name> -+ e:<enabled> -+ u:<update mode> -+ t:<tear sync on/off> -+ h:<xres/hfp/hbp/hsw> -+ v:<yres/vfp/vbp/vsw> -+ p:<pix clock, in kHz> -+ m:<mode str, as in drivers/video/modedb.c:fb_find_mode> -+ -+There is also a debug sysfs file at /sys/devices/platform/omap-dss/clk which -+shows how DSS has configured the clocks. -+ -+Examples -+-------- -+ -+In the example scripts "omapfb" is a symlink to /sys/devices/platform/omapfb/. -+ -+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 -+ -+Switch from LCD to DVI -+---------------------- -+ -+dviline=`cat omapfb/displays |grep dvi` -+w=`echo $dviline | cut -d " " -f 5 | cut -d ":" -f 2 | cut -d "/" -f 1` -+h=`echo $dviline | cut -d " " -f 6 | cut -d ":" -f 2 | cut -d "/" -f 1` -+ -+echo "lcd e:0" > omapfb/displays -+echo "lcd t:none" > omapfb/managers -+fbset -fb /dev/fb0 -xres $w -yres $h -+# at this point you have to switch the dvi/lcd dip-switch from the omap board -+echo "lcd t:dvi" > omapfb/managers -+echo "dvi e:1" > omapfb/displays -+ -+After this the configuration looks like: -+ -+FB0 --- GFX -\ -- DVI -+FB1 --- VID1 --+- LCD -/ LCD -+FB2 --- VID2 -/ TV ----- TV -+ -+Clone GFX overlay to LCD and TV -+------------------------------- -+ -+tvline=`cat /sys/devices/platform/omapfb/displays |grep tv` -+w=`echo $tvline | cut -d " " -f 5 | cut -d ":" -f 2 | cut -d "/" -f 1` -+h=`echo $tvline | cut -d " " -f 6 | cut -d ":" -f 2 | cut -d "/" -f 1` -+ -+echo "1 t:none" > omapfb/framebuffers -+echo "0 t:gfx,vid1" > omapfb/framebuffers -+echo "gfx e:1" > omapfb/overlays -+echo "vid1 t:tv w:$w h:$h e:1" > omapfb/overlays -+echo "tv e:1" > omapfb/displays -+ -+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. If -+that fails, it will fall back to dma_alloc_writecombine(). -+ -+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. -+ -+Arguments -+--------- -+ -+vram -+ - Amount of total VRAM to preallocate. For example, "10M". -+ -+omapfb.video_mode -+ - Default video mode for default display. For example, -+ "800x400MR-24@60". See drivers/video/modedb.c -+ -+omapfb.vram -+ - VRAM allocated for each framebuffer. Normally omapfb allocates vram -+ depending on the display size. With this you can manually allocate -+ more. For example "4M,3M" allocates 4M for fb0, 3M for fb1. -+ -+omapfb.debug -+ - Enable debug printing. You have to have OMAPFB debug support enabled -+ in kernel config. -+ -+omap-dss.def_disp -+ - Name of default display, to which all overlays will be connected. -+ Common examples are "lcd" or "tv". -+ -+omap-dss.debug -+ - 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() -+ -+Rotate (external FB) -+Rotate (VRFB) -+Rotate (SMS) -+ -+System DMA update for DSI -+- Can be used for RGB16 and RGB24P modes. Probably not for RGB24U (how -+ to skip the empty byte?) -+ -+Power management -+- Context saving -+ -+Resolution change -+- The x/y res of the framebuffer are not display resolutions, but the size -+ of the overlay. -+- The display resolution affects all planes on the display. -+ -+OMAP1 support -+- Not sure if needed -+ -diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig -index 2465aea..cd7d9e2 100644 ---- a/arch/arm/plat-omap/Kconfig -+++ b/arch/arm/plat-omap/Kconfig -@@ -245,6 +245,8 @@ config OMAP_SERIAL_WAKE - to data on the serial RX line. This allows you to wake the - system from serial console. - -+source "arch/arm/plat-omap/dss/Kconfig" -+ - endmenu - - endif -diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile -index 1259846..2740497 100644 ---- a/arch/arm/plat-omap/Makefile -+++ b/arch/arm/plat-omap/Makefile -@@ -29,3 +29,5 @@ obj-$(CONFIG_OMAP_MMU_FWK) += mmu.o - # OMAP mailbox framework - obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox.o - -+# OMAP2/3 Display Subsystem -+obj-y += dss/ -diff --git a/arch/arm/plat-omap/dss/Kconfig b/arch/arm/plat-omap/dss/Kconfig -new file mode 100644 -index 0000000..6b342df ---- /dev/null -+++ b/arch/arm/plat-omap/dss/Kconfig -@@ -0,0 +1,69 @@ -+config 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_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 y -+ -+config OMAP2_DSS_VENC -+ bool "VENC support" -+ default y -+ -+if ARCH_OMAP3 -+ -+config OMAP2_DSS_SDI -+ bool "SDI support" -+ default y -+ -+config OMAP2_DSS_DSI -+ bool "DSI support" -+ default y -+ -+endif -+ -+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. -+ -+config OMAP2_DSS_FAKE_VSYNC -+ bool "Fake VSYNC irq from manual update displays" -+ default n -+ help -+ If this is selected, DSI will fake a DISPC VSYNC interrupt -+ when DSI has sent a frame. -+ -+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 -diff --git a/arch/arm/plat-omap/dss/Makefile b/arch/arm/plat-omap/dss/Makefile -new file mode 100644 -index 0000000..e98c6c1 ---- /dev/null -+++ b/arch/arm/plat-omap/dss/Makefile -@@ -0,0 +1,6 @@ -+obj-$(CONFIG_OMAP2_DSS) += omap-dss.o -+omap-dss-y := dss.o display.o dispc.o dpi.o -+omap-dss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o -+omap-dss-$(CONFIG_OMAP2_DSS_VENC) += venc.o -+omap-dss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o -+omap-dss-$(CONFIG_OMAP2_DSS_DSI) += dsi.o -diff --git a/arch/arm/plat-omap/dss/dispc.c b/arch/arm/plat-omap/dss/dispc.c -new file mode 100644 -index 0000000..20caa48 ---- /dev/null -+++ b/arch/arm/plat-omap/dss/dispc.c -@@ -0,0 +1,2113 @@ -+/* -+ * linux/arch/arm/plat-omap/dss/dispc.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/>. -+ */ -+ -+#define DSS_SUBSYS_NAME "DISPC" -+ -+#include <linux/kernel.h> -+#include <linux/dma-mapping.h> -+#include <linux/vmalloc.h> -+#include <linux/clk.h> -+#include <linux/io.h> -+#include <linux/jiffies.h> -+ -+#include <mach/sram.h> -+#include <mach/board.h> -+#include <mach/clock.h> -+ -+#include <mach/display.h> -+ -+#include "dss.h" -+ -+/* DISPC */ -+#define DISPC_BASE 0x48050400 -+ -+#define DISPC_SZ_REGS SZ_1K -+ -+struct dispc_reg { u16 idx; }; -+ -+#define DISPC_REG(idx) ((const struct dispc_reg) { idx }) -+ -+/* DISPC common */ -+#define DISPC_REVISION DISPC_REG(0x0000) -+#define DISPC_SYSCONFIG DISPC_REG(0x0010) -+#define DISPC_SYSSTATUS DISPC_REG(0x0014) -+#define DISPC_IRQSTATUS DISPC_REG(0x0018) -+#define DISPC_IRQENABLE DISPC_REG(0x001C) -+#define DISPC_CONTROL DISPC_REG(0x0040) -+#define DISPC_CONFIG DISPC_REG(0x0044) -+#define DISPC_CAPABLE DISPC_REG(0x0048) -+#define DISPC_DEFAULT_COLOR0 DISPC_REG(0x004C) -+#define DISPC_DEFAULT_COLOR1 DISPC_REG(0x0050) -+#define DISPC_TRANS_COLOR0 DISPC_REG(0x0054) -+#define DISPC_TRANS_COLOR1 DISPC_REG(0x0058) -+#define DISPC_LINE_STATUS DISPC_REG(0x005C) -+#define DISPC_LINE_NUMBER DISPC_REG(0x0060) -+#define DISPC_TIMING_H DISPC_REG(0x0064) -+#define DISPC_TIMING_V DISPC_REG(0x0068) -+#define DISPC_POL_FREQ DISPC_REG(0x006C) -+#define DISPC_DIVISOR DISPC_REG(0x0070) -+#define DISPC_GLOBAL_ALPHA DISPC_REG(0x0074) -+#define DISPC_SIZE_DIG DISPC_REG(0x0078) -+#define DISPC_SIZE_LCD DISPC_REG(0x007C) -+ -+/* DISPC GFX plane */ -+#define DISPC_GFX_BA0 DISPC_REG(0x0080) -+#define DISPC_GFX_BA1 DISPC_REG(0x0084) -+#define DISPC_GFX_POSITION DISPC_REG(0x0088) -+#define DISPC_GFX_SIZE DISPC_REG(0x008C) -+#define DISPC_GFX_ATTRIBUTES DISPC_REG(0x00A0) -+#define DISPC_GFX_FIFO_THRESHOLD DISPC_REG(0x00A4) -+#define DISPC_GFX_FIFO_SIZE_STATUS DISPC_REG(0x00A8) -+#define DISPC_GFX_ROW_INC DISPC_REG(0x00AC) -+#define DISPC_GFX_PIXEL_INC DISPC_REG(0x00B0) -+#define DISPC_GFX_WINDOW_SKIP DISPC_REG(0x00B4) -+#define DISPC_GFX_TABLE_BA DISPC_REG(0x00B8) -+ -+#define DISPC_DATA_CYCLE1 DISPC_REG(0x01D4) -+#define DISPC_DATA_CYCLE2 DISPC_REG(0x01D8) -+#define DISPC_DATA_CYCLE3 DISPC_REG(0x01DC) -+ -+#define DISPC_CPR_COEF_R DISPC_REG(0x0220) -+#define DISPC_CPR_COEF_G DISPC_REG(0x0224) -+#define DISPC_CPR_COEF_B DISPC_REG(0x0228) -+ -+#define DISPC_GFX_PRELOAD DISPC_REG(0x022C) -+ -+/* DISPC Video plane, n = 0 for VID1 and n = 1 for VID2 */ -+#define DISPC_VID_REG(n, idx) DISPC_REG(0x00BC + (n)*0x90 + idx) -+ -+#define DISPC_VID_BA0(n) DISPC_VID_REG(n, 0x0000) -+#define DISPC_VID_BA1(n) DISPC_VID_REG(n, 0x0004) -+#define DISPC_VID_POSITION(n) DISPC_VID_REG(n, 0x0008) -+#define DISPC_VID_SIZE(n) DISPC_VID_REG(n, 0x000C) -+#define DISPC_VID_ATTRIBUTES(n) DISPC_VID_REG(n, 0x0010) -+#define DISPC_VID_FIFO_THRESHOLD(n) DISPC_VID_REG(n, 0x0014) -+#define DISPC_VID_FIFO_SIZE_STATUS(n) DISPC_VID_REG(n, 0x0018) -+#define DISPC_VID_ROW_INC(n) DISPC_VID_REG(n, 0x001C) -+#define DISPC_VID_PIXEL_INC(n) DISPC_VID_REG(n, 0x0020) -+#define DISPC_VID_FIR(n) DISPC_VID_REG(n, 0x0024) -+#define DISPC_VID_PICTURE_SIZE(n) DISPC_VID_REG(n, 0x0028) -+#define DISPC_VID_ACCU0(n) DISPC_VID_REG(n, 0x002C) -+#define DISPC_VID_ACCU1(n) DISPC_VID_REG(n, 0x0030) -+ -+/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */ -+#define DISPC_VID_FIR_COEF_H(n, i) DISPC_REG(0x00F0 + (n)*0x90 + (i)*0x8) -+/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */ -+#define DISPC_VID_FIR_COEF_HV(n, i) DISPC_REG(0x00F4 + (n)*0x90 + (i)*0x8) -+/* coef index i = {0, 1, 2, 3, 4} */ -+#define DISPC_VID_CONV_COEF(n, i) DISPC_REG(0x0130 + (n)*0x90 + (i)*0x4) -+/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */ -+#define DISPC_VID_FIR_COEF_V(n, i) DISPC_REG(0x01E0 + (n)*0x20 + (i)*0x4) -+ -+#define DISPC_VID_PRELOAD(n) DISPC_REG(0x230 + (n)*0x04) -+ -+ -+#define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \ -+ DISPC_IRQ_OCP_ERR | \ -+ DISPC_IRQ_VID1_FIFO_UNDERFLOW | \ -+ DISPC_IRQ_VID2_FIFO_UNDERFLOW | \ -+ DISPC_IRQ_SYNC_LOST | \ -+ DISPC_IRQ_SYNC_LOST_DIGIT) -+ -+#define DISPC_MAX_NR_ISRS 8 -+ -+static struct { -+ omap_dispc_isr_t isr; -+ void *arg; -+ u32 mask; -+} registered_isr[DISPC_MAX_NR_ISRS]; -+ -+#define REG_GET(idx, start, end) \ -+ FLD_GET(dispc_read_reg(idx), start, end) -+ -+#define REG_FLD_MOD(idx, val, start, end) \ -+ dispc_write_reg(idx, FLD_MOD(dispc_read_reg(idx), val, start, end)) -+ -+static const struct dispc_reg dispc_reg_att[] = { DISPC_GFX_ATTRIBUTES, -+ DISPC_VID_ATTRIBUTES(0), -+ DISPC_VID_ATTRIBUTES(1) }; -+ -+static struct { -+ void __iomem *base; -+ -+ struct clk *dpll4_m4_ck; -+ -+ spinlock_t irq_lock; -+ -+ unsigned long cache_req_pck; -+ unsigned long cache_prate; -+ struct dispc_clock_info cache_cinfo; -+ -+ u32 ctx[DISPC_SZ_REGS / sizeof(u32)]; -+} dispc; -+ -+static inline void dispc_write_reg(const struct dispc_reg idx, u32 val) -+{ -+ __raw_writel(val, dispc.base + idx.idx); -+} -+ -+static inline u32 dispc_read_reg(const struct dispc_reg idx) -+{ -+ return __raw_readl(dispc.base + idx.idx); -+} -+ -+#define SR(reg) \ -+ dispc.ctx[(DISPC_##reg).idx / sizeof(u32)] = dispc_read_reg(DISPC_##reg) -+#define RR(reg) \ -+ dispc_write_reg(DISPC_##reg, dispc.ctx[(DISPC_##reg).idx / sizeof(u32)]) -+ -+void dispc_save_context(void) -+{ -+ if (cpu_is_omap24xx()) -+ return; -+ -+ SR(SYSCONFIG); -+ SR(IRQENABLE); -+ SR(CONTROL); -+ SR(CONFIG); -+ SR(DEFAULT_COLOR0); -+ SR(DEFAULT_COLOR1); -+ SR(TRANS_COLOR0); -+ SR(TRANS_COLOR1); -+ SR(LINE_NUMBER); -+ SR(TIMING_H); -+ SR(TIMING_V); -+ SR(POL_FREQ); -+ SR(DIVISOR); -+ SR(GLOBAL_ALPHA); -+ SR(SIZE_DIG); -+ SR(SIZE_LCD); -+ -+ SR(GFX_BA0); -+ SR(GFX_BA1); -+ SR(GFX_POSITION); -+ SR(GFX_SIZE); -+ SR(GFX_ATTRIBUTES); -+ SR(GFX_FIFO_THRESHOLD); -+ SR(GFX_ROW_INC); -+ SR(GFX_PIXEL_INC); -+ SR(GFX_WINDOW_SKIP); -+ SR(GFX_TABLE_BA); -+ -+ SR(DATA_CYCLE1); -+ SR(DATA_CYCLE2); -+ SR(DATA_CYCLE3); -+ -+ SR(CPR_COEF_R); -+ SR(CPR_COEF_G); -+ SR(CPR_COEF_B); -+ -+ SR(GFX_PRELOAD); -+ -+ /* VID1 */ -+ SR(VID_BA0(0)); -+ SR(VID_BA1(0)); -+ SR(VID_POSITION(0)); -+ SR(VID_SIZE(0)); -+ SR(VID_ATTRIBUTES(0)); -+ SR(VID_FIFO_THRESHOLD(0)); -+ SR(VID_ROW_INC(0)); -+ SR(VID_PIXEL_INC(0)); -+ SR(VID_FIR(0)); -+ SR(VID_PICTURE_SIZE(0)); -+ SR(VID_ACCU0(0)); -+ SR(VID_ACCU1(0)); -+ -+ SR(VID_FIR_COEF_H(0, 0)); -+ SR(VID_FIR_COEF_H(0, 1)); -+ SR(VID_FIR_COEF_H(0, 2)); -+ SR(VID_FIR_COEF_H(0, 3)); -+ SR(VID_FIR_COEF_H(0, 4)); -+ SR(VID_FIR_COEF_H(0, 5)); -+ SR(VID_FIR_COEF_H(0, 6)); -+ SR(VID_FIR_COEF_H(0, 7)); -+ -+ SR(VID_FIR_COEF_HV(0, 0)); -+ SR(VID_FIR_COEF_HV(0, 1)); -+ SR(VID_FIR_COEF_HV(0, 2)); -+ SR(VID_FIR_COEF_HV(0, 3)); -+ SR(VID_FIR_COEF_HV(0, 4)); -+ SR(VID_FIR_COEF_HV(0, 5)); -+ SR(VID_FIR_COEF_HV(0, 6)); -+ SR(VID_FIR_COEF_HV(0, 7)); -+ -+ SR(VID_CONV_COEF(0, 0)); -+ SR(VID_CONV_COEF(0, 1)); -+ SR(VID_CONV_COEF(0, 2)); -+ SR(VID_CONV_COEF(0, 3)); -+ SR(VID_CONV_COEF(0, 4)); -+ -+ SR(VID_FIR_COEF_V(0, 0)); -+ SR(VID_FIR_COEF_V(0, 1)); -+ SR(VID_FIR_COEF_V(0, 2)); -+ SR(VID_FIR_COEF_V(0, 3)); -+ SR(VID_FIR_COEF_V(0, 4)); -+ SR(VID_FIR_COEF_V(0, 5)); -+ SR(VID_FIR_COEF_V(0, 6)); -+ SR(VID_FIR_COEF_V(0, 7)); -+ -+ SR(VID_PRELOAD(0)); -+ -+ /* VID2 */ -+ SR(VID_BA0(1)); -+ SR(VID_BA1(1)); -+ SR(VID_POSITION(1)); -+ SR(VID_SIZE(1)); -+ SR(VID_ATTRIBUTES(1)); -+ SR(VID_FIFO_THRESHOLD(1)); -+ SR(VID_ROW_INC(1)); -+ SR(VID_PIXEL_INC(1)); -+ SR(VID_FIR(1)); -+ SR(VID_PICTURE_SIZE(1)); -+ SR(VID_ACCU0(1)); -+ SR(VID_ACCU1(1)); -+ -+ SR(VID_FIR_COEF_H(1, 0)); -+ SR(VID_FIR_COEF_H(1, 1)); -+ SR(VID_FIR_COEF_H(1, 2)); -+ SR(VID_FIR_COEF_H(1, 3)); -+ SR(VID_FIR_COEF_H(1, 4)); -+ SR(VID_FIR_COEF_H(1, 5)); -+ SR(VID_FIR_COEF_H(1, 6)); -+ SR(VID_FIR_COEF_H(1, 7)); -+ -+ SR(VID_FIR_COEF_HV(1, 0)); -+ SR(VID_FIR_COEF_HV(1, 1)); -+ SR(VID_FIR_COEF_HV(1, 2)); -+ SR(VID_FIR_COEF_HV(1, 3)); -+ SR(VID_FIR_COEF_HV(1, 4)); -+ SR(VID_FIR_COEF_HV(1, 5)); -+ SR(VID_FIR_COEF_HV(1, 6)); -+ SR(VID_FIR_COEF_HV(1, 7)); -+ -+ SR(VID_CONV_COEF(1, 0)); -+ SR(VID_CONV_COEF(1, 1)); -+ SR(VID_CONV_COEF(1, 2)); -+ SR(VID_CONV_COEF(1, 3)); -+ SR(VID_CONV_COEF(1, 4)); -+ -+ SR(VID_FIR_COEF_V(1, 0)); -+ SR(VID_FIR_COEF_V(1, 1)); -+ SR(VID_FIR_COEF_V(1, 2)); -+ SR(VID_FIR_COEF_V(1, 3)); -+ SR(VID_FIR_COEF_V(1, 4)); -+ SR(VID_FIR_COEF_V(1, 5)); -+ SR(VID_FIR_COEF_V(1, 6)); -+ SR(VID_FIR_COEF_V(1, 7)); -+ -+ SR(VID_PRELOAD(1)); -+} -+ -+void dispc_restore_context(void) -+{ -+ RR(SYSCONFIG); -+ RR(IRQENABLE); -+ /*RR(CONTROL);*/ -+ RR(CONFIG); -+ RR(DEFAULT_COLOR0); -+ RR(DEFAULT_COLOR1); -+ RR(TRANS_COLOR0); -+ RR(TRANS_COLOR1); -+ RR(LINE_NUMBER); -+ RR(TIMING_H); -+ RR(TIMING_V); -+ RR(POL_FREQ); -+ RR(DIVISOR); -+ RR(GLOBAL_ALPHA); -+ RR(SIZE_DIG); -+ RR(SIZE_LCD); -+ -+ RR(GFX_BA0); -+ RR(GFX_BA1); -+ RR(GFX_POSITION); -+ RR(GFX_SIZE); -+ RR(GFX_ATTRIBUTES); -+ RR(GFX_FIFO_THRESHOLD); -+ RR(GFX_ROW_INC); -+ RR(GFX_PIXEL_INC); -+ RR(GFX_WINDOW_SKIP); -+ RR(GFX_TABLE_BA); -+ -+ RR(DATA_CYCLE1); -+ RR(DATA_CYCLE2); -+ RR(DATA_CYCLE3); -+ -+ RR(CPR_COEF_R); -+ RR(CPR_COEF_G); -+ RR(CPR_COEF_B); -+ -+ RR(GFX_PRELOAD); -+ -+ /* VID1 */ -+ RR(VID_BA0(0)); -+ RR(VID_BA1(0)); -+ RR(VID_POSITION(0)); -+ RR(VID_SIZE(0)); -+ RR(VID_ATTRIBUTES(0)); -+ RR(VID_FIFO_THRESHOLD(0)); -+ RR(VID_ROW_INC(0)); -+ RR(VID_PIXEL_INC(0)); -+ RR(VID_FIR(0)); -+ RR(VID_PICTURE_SIZE(0)); -+ RR(VID_ACCU0(0)); -+ RR(VID_ACCU1(0)); -+ -+ RR(VID_FIR_COEF_H(0, 0)); -+ RR(VID_FIR_COEF_H(0, 1)); -+ RR(VID_FIR_COEF_H(0, 2)); -+ RR(VID_FIR_COEF_H(0, 3)); -+ RR(VID_FIR_COEF_H(0, 4)); -+ RR(VID_FIR_COEF_H(0, 5)); -+ RR(VID_FIR_COEF_H(0, 6)); -+ RR(VID_FIR_COEF_H(0, 7)); -+ -+ RR(VID_FIR_COEF_HV(0, 0)); -+ RR(VID_FIR_COEF_HV(0, 1)); -+ RR(VID_FIR_COEF_HV(0, 2)); -+ RR(VID_FIR_COEF_HV(0, 3)); -+ RR(VID_FIR_COEF_HV(0, 4)); -+ RR(VID_FIR_COEF_HV(0, 5)); -+ RR(VID_FIR_COEF_HV(0, 6)); -+ RR(VID_FIR_COEF_HV(0, 7)); -+ -+ RR(VID_CONV_COEF(0, 0)); -+ RR(VID_CONV_COEF(0, 1)); -+ RR(VID_CONV_COEF(0, 2)); -+ RR(VID_CONV_COEF(0, 3)); -+ RR(VID_CONV_COEF(0, 4)); -+ -+ RR(VID_FIR_COEF_V(0, 0)); -+ RR(VID_FIR_COEF_V(0, 1)); -+ RR(VID_FIR_COEF_V(0, 2)); -+ RR(VID_FIR_COEF_V(0, 3)); -+ RR(VID_FIR_COEF_V(0, 4)); -+ RR(VID_FIR_COEF_V(0, 5)); -+ RR(VID_FIR_COEF_V(0, 6)); -+ RR(VID_FIR_COEF_V(0, 7)); -+ -+ RR(VID_PRELOAD(0)); -+ -+ /* VID2 */ -+ RR(VID_BA0(1)); -+ RR(VID_BA1(1)); -+ RR(VID_POSITION(1)); -+ RR(VID_SIZE(1)); -+ RR(VID_ATTRIBUTES(1)); -+ RR(VID_FIFO_THRESHOLD(1)); -+ RR(VID_ROW_INC(1)); -+ RR(VID_PIXEL_INC(1)); -+ RR(VID_FIR(1)); -+ RR(VID_PICTURE_SIZE(1)); -+ RR(VID_ACCU0(1)); -+ RR(VID_ACCU1(1)); -+ -+ RR(VID_FIR_COEF_H(1, 0)); -+ RR(VID_FIR_COEF_H(1, 1)); -+ RR(VID_FIR_COEF_H(1, 2)); -+ RR(VID_FIR_COEF_H(1, 3)); -+ RR(VID_FIR_COEF_H(1, 4)); -+ RR(VID_FIR_COEF_H(1, 5)); -+ RR(VID_FIR_COEF_H(1, 6)); -+ RR(VID_FIR_COEF_H(1, 7)); -+ -+ RR(VID_FIR_COEF_HV(1, 0)); -+ RR(VID_FIR_COEF_HV(1, 1)); -+ RR(VID_FIR_COEF_HV(1, 2)); -+ RR(VID_FIR_COEF_HV(1, 3)); -+ RR(VID_FIR_COEF_HV(1, 4)); -+ RR(VID_FIR_COEF_HV(1, 5)); -+ RR(VID_FIR_COEF_HV(1, 6)); -+ RR(VID_FIR_COEF_HV(1, 7)); -+ -+ RR(VID_CONV_COEF(1, 0)); -+ RR(VID_CONV_COEF(1, 1)); -+ RR(VID_CONV_COEF(1, 2)); -+ RR(VID_CONV_COEF(1, 3)); -+ RR(VID_CONV_COEF(1, 4)); -+ -+ RR(VID_FIR_COEF_V(1, 0)); -+ RR(VID_FIR_COEF_V(1, 1)); -+ RR(VID_FIR_COEF_V(1, 2)); -+ RR(VID_FIR_COEF_V(1, 3)); -+ RR(VID_FIR_COEF_V(1, 4)); -+ RR(VID_FIR_COEF_V(1, 5)); -+ RR(VID_FIR_COEF_V(1, 6)); -+ RR(VID_FIR_COEF_V(1, 7)); -+ -+ RR(VID_PRELOAD(1)); -+ -+ /* enable last, because LCD & DIGIT enable are here */ -+ RR(CONTROL); -+} -+ -+#undef SR -+#undef RR -+ -+static inline void enable_clocks(int enable) -+{ -+ if (enable) -+ dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); -+ else -+ dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); -+} -+ -+void dispc_go(enum omap_channel channel) -+{ -+ int bit; -+ unsigned long tmo; -+ -+ enable_clocks(1); -+ -+ if (channel == OMAP_DSS_CHANNEL_LCD) -+ bit = 0; /* LCDENABLE */ -+ else -+ bit = 1; /* DIGITALENABLE */ -+ -+ /* if the channel is not enabled, we don't need GO */ -+ if (REG_GET(DISPC_CONTROL, bit, bit) == 0) -+ goto end; -+ -+ if (channel == OMAP_DSS_CHANNEL_LCD) -+ bit = 5; /* GOLCD */ -+ else -+ bit = 6; /* GODIGIT */ -+ -+ tmo = jiffies + msecs_to_jiffies(200); -+ while (REG_GET(DISPC_CONTROL, bit, bit) == 1) { -+ if (time_after(jiffies, tmo)) { -+ DSSERR("timeout waiting GO flag\n"); -+ goto end; -+ } -+ cpu_relax(); -+ } -+ -+ DSSDBG("GO %s\n", channel == OMAP_DSS_CHANNEL_LCD ? "LCD" : "DIGIT"); -+ -+ REG_FLD_MOD(DISPC_CONTROL, 1, bit, bit); -+end: -+ enable_clocks(0); -+} -+ -+static void _dispc_write_firh_reg(enum omap_plane plane, int reg, u32 value) -+{ -+ BUG_ON(plane == OMAP_DSS_GFX); -+ -+ dispc_write_reg(DISPC_VID_FIR_COEF_H(plane-1, reg), value); -+} -+ -+static void _dispc_write_firhv_reg(enum omap_plane plane, int reg, u32 value) -+{ -+ BUG_ON(plane == OMAP_DSS_GFX); -+ -+ dispc_write_reg(DISPC_VID_FIR_COEF_HV(plane-1, reg), value); -+} -+ -+ -+static void _dispc_set_scale_coef(enum omap_plane plane, int hscaleup, -+ int vscaleup) -+{ -+ /* Coefficients for horizontal up-sampling */ -+ const u32 coef_hup[8] = { -+ 0x00800000, -+ 0x0D7CF800, -+ 0x1E70F5FF, -+ 0x335FF5FE, -+ 0xF74949F7, -+ 0xF55F33FB, -+ 0xF5701EFE, -+ 0xF87C0DFF, -+ }; -+ -+ /* Coefficients for horizontal down-sampling */ -+ const u32 coef_hdown[8] = { -+ 0x24382400, -+ 0x28371FFE, -+ 0x2C361BFB, -+ 0x303516F9, -+ 0x11343311, -+ 0x1635300C, -+ 0x1B362C08, -+ 0x1F372804, -+ }; -+ -+ /* Coefficients for horizontal and vertical up-sampling */ -+ const u32 coef_hvup[8] = { -+ 0x00800000, -+ 0x037B02FF, -+ 0x0C6F05FE, -+ 0x205907FB, -+ 0x00404000, -+ 0x075920FE, -+ 0x056F0CFF, -+ 0x027B0300, -+ }; -+ -+ /* Coefficients for horizontal and vertical down-sampling */ -+ const u32 coef_hvdown[8] = { -+ 0x24382400, -+ 0x28391F04, -+ 0x2D381B08, -+ 0x3237170C, -+ 0x123737F7, -+ 0x173732F9, -+ 0x1B382DFB, -+ 0x1F3928FE, -+ }; -+ -+ const u32 *h_coef; -+ const u32 *hv_coef; -+ const u32 *hv_coef_mod; -+ int i; -+ -+ if (hscaleup) -+ h_coef = coef_hup; -+ else -+ h_coef = coef_hdown; -+ -+ if (vscaleup) { -+ hv_coef = coef_hvup; -+ -+ if (hscaleup) -+ hv_coef_mod = NULL; -+ else -+ hv_coef_mod = coef_hvdown; -+ } else { -+ hv_coef = coef_hvdown; -+ -+ if (hscaleup) -+ hv_coef_mod = coef_hvup; -+ else -+ hv_coef_mod = NULL; -+ } -+ -+ for (i = 0; i < 8; i++) { -+ u32 h, hv; -+ -+ h = h_coef[i]; -+ -+ hv = hv_coef[i]; -+ -+ if (hv_coef_mod) { -+ hv &= 0xffffff00; -+ hv |= (hv_coef_mod[i] & 0xff); -+ } -+ -+ _dispc_write_firh_reg(plane, i, h); -+ _dispc_write_firhv_reg(plane, i, hv); -+ } -+} -+ -+static void _dispc_setup_color_conv_coef(void) -+{ -+ const struct color_conv_coef { -+ int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb; -+ int full_range; -+ } ctbl_bt601_5 = { -+ 298, 409, 0, 298, -208, -100, 298, 0, 517, 0, -+ }; -+ -+ const struct color_conv_coef *ct; -+ -+#define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0)) -+ -+ ct = &ctbl_bt601_5; -+ -+ dispc_write_reg(DISPC_VID_CONV_COEF(0, 0), CVAL(ct->rcr, ct->ry)); -+ dispc_write_reg(DISPC_VID_CONV_COEF(0, 1), CVAL(ct->gy, ct->rcb)); -+ dispc_write_reg(DISPC_VID_CONV_COEF(0, 2), CVAL(ct->gcb, ct->gcr)); -+ dispc_write_reg(DISPC_VID_CONV_COEF(0, 3), CVAL(ct->bcr, ct->by)); -+ dispc_write_reg(DISPC_VID_CONV_COEF(0, 4), CVAL(0, ct->bcb)); -+ -+ dispc_write_reg(DISPC_VID_CONV_COEF(1, 0), CVAL(ct->rcr, ct->ry)); -+ dispc_write_reg(DISPC_VID_CONV_COEF(1, 1), CVAL(ct->gy, ct->rcb)); -+ dispc_write_reg(DISPC_VID_CONV_COEF(1, 2), CVAL(ct->gcb, ct->gcr)); -+ dispc_write_reg(DISPC_VID_CONV_COEF(1, 3), CVAL(ct->bcr, ct->by)); -+ dispc_write_reg(DISPC_VID_CONV_COEF(1, 4), CVAL(0, ct->bcb)); -+ -+#undef CVAL -+ -+ REG_FLD_MOD(DISPC_VID_ATTRIBUTES(0), ct->full_range, 11, 11); -+ REG_FLD_MOD(DISPC_VID_ATTRIBUTES(1), ct->full_range, 11, 11); -+} -+ -+ -+static void _dispc_set_plane_ba0(enum omap_plane plane, u32 paddr) -+{ -+ const struct dispc_reg ba0_reg[] = { DISPC_GFX_BA0, -+ DISPC_VID_BA0(0), -+ DISPC_VID_BA0(1) }; -+ -+ dispc_write_reg(ba0_reg[plane], paddr); -+} -+ -+static void _dispc_set_plane_ba1(enum omap_plane plane, u32 paddr) -+{ -+ const struct dispc_reg ba1_reg[] = { DISPC_GFX_BA1, -+ DISPC_VID_BA1(0), -+ DISPC_VID_BA1(1) }; -+ -+ dispc_write_reg(ba1_reg[plane], paddr); -+} -+ -+static void _dispc_set_plane_pos(enum omap_plane plane, int x, int y) -+{ -+ const struct dispc_reg pos_reg[] = { DISPC_GFX_POSITION, -+ DISPC_VID_POSITION(0), -+ DISPC_VID_POSITION(1) }; -+ -+ u32 val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0); -+ dispc_write_reg(pos_reg[plane], val); -+} -+ -+static void _dispc_set_pic_size(enum omap_plane plane, int width, int height) -+{ -+ const struct dispc_reg siz_reg[] = { DISPC_GFX_SIZE, -+ DISPC_VID_PICTURE_SIZE(0), -+ DISPC_VID_PICTURE_SIZE(1) }; -+ u32 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); -+ dispc_write_reg(siz_reg[plane], val); -+} -+ -+static void _dispc_set_vid_size(enum omap_plane plane, int width, int height) -+{ -+ u32 val; -+ const struct dispc_reg vsi_reg[] = { DISPC_VID_SIZE(0), -+ DISPC_VID_SIZE(1) }; -+ -+ BUG_ON(plane == OMAP_DSS_GFX); -+ -+ val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); -+ dispc_write_reg(vsi_reg[plane-1], val); -+} -+ -+static void _dispc_set_row_inc(enum omap_plane plane, int inc) -+{ -+ const struct dispc_reg ri_reg[] = { DISPC_GFX_ROW_INC, -+ DISPC_VID_ROW_INC(0), -+ DISPC_VID_ROW_INC(1) }; -+ -+ dispc_write_reg(ri_reg[plane], inc); -+} -+ -+static void _dispc_set_color_mode(enum omap_plane plane, -+ enum omap_color_mode color_mode) -+{ -+ u32 m = 0; -+ -+ switch (color_mode) { -+ case OMAP_DSS_COLOR_CLUT1: -+ m = 0x0; break; -+ case OMAP_DSS_COLOR_CLUT2: -+ m = 0x1; break; -+ case OMAP_DSS_COLOR_CLUT4: -+ m = 0x2; break; -+ case OMAP_DSS_COLOR_CLUT8: -+ m = 0x3; break; -+ case OMAP_DSS_COLOR_RGB12U: -+ m = 0x4; break; -+ case OMAP_DSS_COLOR_ARGB16: -+ m = 0x5; break; -+ case OMAP_DSS_COLOR_RGB16: -+ m = 0x6; break; -+ case OMAP_DSS_COLOR_RGB24U: -+ m = 0x8; break; -+ case OMAP_DSS_COLOR_RGB24P: -+ m = 0x9; break; -+ case OMAP_DSS_COLOR_YUV2: -+ m = 0xa; break; -+ case OMAP_DSS_COLOR_UYVY: -+ m = 0xb; break; -+ case OMAP_DSS_COLOR_ARGB32: -+ m = 0xc; break; -+ case OMAP_DSS_COLOR_RGBA32: -+ m = 0xd; break; -+ case OMAP_DSS_COLOR_RGBX32: -+ m = 0xe; break; -+ default: -+ BUG(); break; -+ } -+ -+ REG_FLD_MOD(dispc_reg_att[plane], m, 4, 1); -+} -+ -+static void _dispc_set_channel_out(enum omap_plane plane, -+ enum omap_channel channel) -+{ -+ int shift; -+ u32 val; -+ -+ switch (plane) { -+ case OMAP_DSS_GFX: -+ shift = 8; -+ break; -+ case OMAP_DSS_VIDEO1: -+ case OMAP_DSS_VIDEO2: -+ shift = 16; -+ break; -+ default: -+ BUG(); -+ return; -+ } -+ -+ val = dispc_read_reg(dispc_reg_att[plane]); -+ val = FLD_MOD(val, channel, shift, shift); -+ dispc_write_reg(dispc_reg_att[plane], val); -+} -+ -+void dispc_set_burst_size(enum omap_plane plane, -+ enum omap_burst_size burst_size) -+{ -+ int shift; -+ u32 val; -+ -+ enable_clocks(1); -+ -+ switch (plane) { -+ case OMAP_DSS_GFX: -+ shift = 6; -+ break; -+ case OMAP_DSS_VIDEO1: -+ case OMAP_DSS_VIDEO2: -+ shift = 14; -+ break; -+ default: -+ BUG(); -+ return; -+ } -+ -+ val = dispc_read_reg(dispc_reg_att[plane]); -+ val = FLD_MOD(val, burst_size, shift+1, shift); -+ dispc_write_reg(dispc_reg_att[plane], val); -+ -+ enable_clocks(0); -+} -+ -+static void _dispc_set_vid_color_conv(enum omap_plane plane, int enable) -+{ -+ u32 val; -+ -+ BUG_ON(plane == OMAP_DSS_GFX); -+ -+ val = dispc_read_reg(dispc_reg_att[plane]); -+ val = FLD_MOD(val, enable, 9, 9); -+ dispc_write_reg(dispc_reg_att[plane], val); -+} -+ -+void dispc_set_lcd_size(int width, int height) -+{ -+ u32 val; -+ BUG_ON((width > (1 << 11)) || (height > (1 << 11))); -+ val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); -+ enable_clocks(1); -+ dispc_write_reg(DISPC_SIZE_LCD, val); -+ enable_clocks(0); -+} -+ -+void dispc_set_digit_size(int width, int height) -+{ -+ u32 val; -+ BUG_ON((width > (1 << 11)) || (height > (1 << 11))); -+ val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); -+ enable_clocks(1); -+ dispc_write_reg(DISPC_SIZE_DIG, val); -+ enable_clocks(0); -+} -+ -+u32 dispc_get_plane_fifo_size(enum omap_plane plane) -+{ -+ const struct dispc_reg fsz_reg[] = { DISPC_GFX_FIFO_SIZE_STATUS, -+ DISPC_VID_FIFO_SIZE_STATUS(0), -+ DISPC_VID_FIFO_SIZE_STATUS(1) }; -+ u32 size; -+ -+ enable_clocks(1); -+ -+ if (cpu_is_omap24xx()) -+ size = FLD_GET(dispc_read_reg(fsz_reg[plane]), 8, 0); -+ else if (cpu_is_omap34xx()) -+ size = FLD_GET(dispc_read_reg(fsz_reg[plane]), 10, 0); -+ else -+ BUG(); -+ -+ enable_clocks(0); -+ -+ return size; -+} -+ -+void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high) -+{ -+ const struct dispc_reg ftrs_reg[] = { DISPC_GFX_FIFO_THRESHOLD, -+ DISPC_VID_FIFO_THRESHOLD(0), -+ DISPC_VID_FIFO_THRESHOLD(1) }; -+ const struct dispc_reg fsz_reg[] = { DISPC_GFX_FIFO_SIZE_STATUS, -+ DISPC_VID_FIFO_SIZE_STATUS(0), -+ DISPC_VID_FIFO_SIZE_STATUS(1) }; -+ u32 size; -+ -+ enable_clocks(1); -+ -+ if (cpu_is_omap24xx()) -+ size = FLD_GET(dispc_read_reg(fsz_reg[plane]), 8, 0); -+ else if (cpu_is_omap34xx()) -+ size = FLD_GET(dispc_read_reg(fsz_reg[plane]), 10, 0); -+ else -+ BUG(); -+ -+ BUG_ON(low > size || high > size); -+ -+ DSSDBG("fifo(%d) size %d, low/high old %u/%u, new %u/%u\n", -+ plane, size, -+ REG_GET(ftrs_reg[plane], 11, 0), -+ REG_GET(ftrs_reg[plane], 27, 16), -+ low, high); -+ -+ if (cpu_is_omap24xx()) -+ dispc_write_reg(ftrs_reg[plane], -+ FLD_VAL(high, 24, 16) | FLD_VAL(low, 8, 0)); -+ else -+ dispc_write_reg(ftrs_reg[plane], -+ FLD_VAL(high, 27, 16) | FLD_VAL(low, 11, 0)); -+ -+ enable_clocks(0); -+} -+ -+static void _dispc_set_fir(enum omap_plane plane, int hinc, int vinc) -+{ -+ u32 val; -+ const struct dispc_reg fir_reg[] = { DISPC_VID_FIR(0), -+ DISPC_VID_FIR(1) }; -+ -+ BUG_ON(plane == OMAP_DSS_GFX); -+ -+ val = FLD_VAL(vinc, 27, 16) | FLD_VAL(hinc, 11, 0); -+ dispc_write_reg(fir_reg[plane-1], val); -+} -+ -+static void _dispc_set_vid_accu0(enum omap_plane plane, int haccu, int vaccu) -+{ -+ u32 val; -+ const struct dispc_reg ac0_reg[] = { DISPC_VID_ACCU0(0), -+ DISPC_VID_ACCU0(1) }; -+ -+ BUG_ON(plane == OMAP_DSS_GFX); -+ -+ val = FLD_VAL(vaccu, 25, 16) | FLD_VAL(haccu, 9, 0); -+ dispc_write_reg(ac0_reg[plane-1], val); -+} -+ -+static void _dispc_set_vid_accu1(enum omap_plane plane, int haccu, int vaccu) -+{ -+ u32 val; -+ const struct dispc_reg ac1_reg[] = { DISPC_VID_ACCU1(0), -+ DISPC_VID_ACCU1(1) }; -+ -+ BUG_ON(plane == OMAP_DSS_GFX); -+ -+ val = FLD_VAL(vaccu, 25, 16) | FLD_VAL(haccu, 9, 0); -+ dispc_write_reg(ac1_reg[plane-1], val); -+} -+ -+ -+static void _dispc_set_scaling(enum omap_plane plane, -+ int orig_width, int orig_height, -+ int out_width, int out_height, -+ int ilace) -+{ -+ int fir_hinc; -+ int fir_vinc; -+ int hscaleup, vscaleup; -+ int fieldmode = 0; -+ int accu0 = 0; -+ int accu1 = 0; -+ u32 l; -+ -+ BUG_ON(plane == OMAP_DSS_GFX); -+ -+ hscaleup = orig_width <= out_width; -+ vscaleup = orig_height <= out_height; -+ -+ _dispc_set_scale_coef(plane, hscaleup, vscaleup); -+ -+ if (!orig_width || orig_width == out_width) -+ fir_hinc = 0; -+ else -+ fir_hinc = 1024 * orig_width / out_width; -+ -+ if (!orig_height || orig_height == out_height) -+ fir_vinc = 0; -+ else -+ fir_vinc = 1024 * orig_height / out_height; -+ -+ _dispc_set_fir(plane, fir_hinc, fir_vinc); -+ -+ l = dispc_read_reg(dispc_reg_att[plane]); -+ l &= ~(0x0f << 5); -+ -+ l |= fir_hinc ? (1 << 5) : 0; -+ l |= fir_vinc ? (1 << 6) : 0; -+ -+ l |= hscaleup ? 0 : (1 << 7); -+ l |= vscaleup ? 0 : (1 << 8); -+ -+ dispc_write_reg(dispc_reg_att[plane], l); -+ -+ if (ilace) { -+ if (fieldmode) { -+ accu0 = fir_vinc / 2; -+ accu1 = 0; -+ } else { -+ accu0 = 0; -+ accu1 = fir_vinc / 2; -+ if (accu1 >= 1024/2) { -+ accu0 = 1024/2; -+ accu1 -= accu0; -+ } -+ } -+ } -+ -+ _dispc_set_vid_accu0(plane, 0, accu0); -+ _dispc_set_vid_accu1(plane, 0, accu1); -+} -+ -+static int _dispc_setup_plane(enum omap_plane plane, -+ enum omap_channel channel_out, -+ u32 paddr, int screen_width, -+ int pos_x, int pos_y, -+ int width, int height, -+ int out_width, int out_height, -+ enum omap_color_mode color_mode, -+ int ilace) -+{ -+ int fieldmode = 0; -+ int bpp; -+ int cconv; -+ int scaling = 0; -+ -+ if (plane == OMAP_DSS_GFX) { -+ if (width != out_width || height != out_height) -+ return -EINVAL; -+ } else { -+ /* video plane */ -+ if (width != out_width || height != out_height) -+ scaling = 1; -+ -+ if (out_width < width/2 || -+ out_width > width*8) -+ return -EINVAL; -+ -+ if (out_height < height/2 || -+ out_height > height*8) -+ return -EINVAL; -+ } -+ -+ -+ switch (color_mode) { -+ case OMAP_DSS_COLOR_RGB16: -+ bpp = 16; -+ cconv = 0; -+ break; -+ -+ case OMAP_DSS_COLOR_RGB24P: -+ bpp = 24; -+ cconv = 0; -+ break; -+ -+ case OMAP_DSS_COLOR_RGB24U: -+ bpp = 32; -+ cconv = 0; -+ break; -+ -+ case OMAP_DSS_COLOR_YUV2: -+ case OMAP_DSS_COLOR_UYVY: -+ BUG_ON(plane == OMAP_DSS_GFX); -+ bpp = 16; -+ cconv = 1; -+ break; -+ -+ default: -+ BUG(); -+ return 1; -+ } -+ -+ if (ilace) { -+ if (height == out_height || height > out_height) -+ fieldmode = 1; -+ } -+ -+ if (fieldmode) -+ height /= 2; -+ -+ if (ilace) -+ out_height /= 2; -+ -+ if (plane != OMAP_DSS_GFX) -+ _dispc_set_scaling(plane, width, height, -+ out_width, out_height, -+ ilace); -+ -+ /* attributes */ -+ _dispc_set_channel_out(plane, channel_out); -+ _dispc_set_color_mode(plane, color_mode); -+ if (plane != OMAP_DSS_GFX) -+ _dispc_set_vid_color_conv(plane, cconv); -+ -+ /* */ -+ -+ _dispc_set_plane_ba0(plane, paddr); -+ -+ if (fieldmode) -+ _dispc_set_plane_ba1(plane, paddr + screen_width * bpp/8); -+ else -+ _dispc_set_plane_ba1(plane, paddr); -+ -+ -+ _dispc_set_plane_pos(plane, pos_x, pos_y); -+ -+ _dispc_set_pic_size(plane, width, height); -+ -+ if (plane != OMAP_DSS_GFX) -+ _dispc_set_vid_size(plane, out_width, out_height); -+ -+ _dispc_set_row_inc(plane, -+ (screen_width - width) * bpp / 8 + -+ (fieldmode ? screen_width * bpp / 8 : 0) + -+ 1); -+ -+ return 0; -+} -+ -+static void _dispc_enable_plane(enum omap_plane plane, int enable) -+{ -+ REG_FLD_MOD(dispc_reg_att[plane], enable ? 1 : 0, 0, 0); -+} -+ -+ -+void dispc_enable_lcd_out(int enable) -+{ -+ enable_clocks(1); -+ REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 0, 0); -+ enable_clocks(0); -+} -+ -+void dispc_enable_digit_out(int enable) -+{ -+ enable_clocks(1); -+ REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 1, 1); -+ enable_clocks(0); -+} -+ -+void dispc_lcd_enable_signal_polarity(int act_high) -+{ -+ enable_clocks(1); -+ REG_FLD_MOD(DISPC_CONTROL, act_high ? 1 : 0, 29, 29); -+ enable_clocks(0); -+} -+ -+void dispc_lcd_enable_signal(int enable) -+{ -+ enable_clocks(1); -+ REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 28, 28); -+ enable_clocks(0); -+} -+ -+void dispc_pck_free_enable(int enable) -+{ -+ enable_clocks(1); -+ REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 27, 27); -+ enable_clocks(0); -+} -+ -+void dispc_enable_fifohandcheck(int enable) -+{ -+ enable_clocks(1); -+ REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 16, 16); -+ enable_clocks(0); -+} -+ -+ -+void dispc_set_lcd_display_type(enum omap_lcd_display_type type) -+{ -+ int mode; -+ -+ switch (type) { -+ case OMAP_DSS_LCD_DISPLAY_STN: -+ mode = 0; -+ break; -+ -+ case OMAP_DSS_LCD_DISPLAY_TFT: -+ mode = 1; -+ break; -+ -+ default: -+ BUG(); -+ return; -+ } -+ -+ enable_clocks(1); -+ REG_FLD_MOD(DISPC_CONTROL, mode, 3, 3); -+ enable_clocks(0); -+} -+ -+void dispc_set_loadmode(enum omap_dss_load_mode mode) -+{ -+ enable_clocks(1); -+ REG_FLD_MOD(DISPC_CONFIG, mode, 2, 1); -+ enable_clocks(0); -+} -+ -+ -+void omap_dispc_set_default_color(enum omap_channel channel, u32 color) -+{ -+ const struct dispc_reg def_reg[] = { DISPC_DEFAULT_COLOR0, -+ DISPC_DEFAULT_COLOR1 }; -+ -+ enable_clocks(1); -+ dispc_write_reg(def_reg[channel], color); -+ enable_clocks(0); -+} -+ -+void omap_dispc_set_trans_key(enum omap_channel ch, -+ enum omap_dss_color_key_type type, -+ u32 trans_key) -+{ -+ const struct dispc_reg tr_reg[] = { -+ DISPC_TRANS_COLOR0, DISPC_TRANS_COLOR1 }; -+ -+ enable_clocks(1); -+ if (ch == OMAP_DSS_CHANNEL_LCD) -+ REG_FLD_MOD(DISPC_CONFIG, type, 11, 11); -+ else /* OMAP_DSS_CHANNEL_DIGIT */ -+ REG_FLD_MOD(DISPC_CONFIG, type, 13, 13); -+ -+ dispc_write_reg(tr_reg[ch], trans_key); -+ enable_clocks(0); -+} -+ -+void omap_dispc_enable_trans_key(enum omap_channel ch, int enable) -+{ -+ enable_clocks(1); -+ if (ch == OMAP_DSS_CHANNEL_LCD) -+ REG_FLD_MOD(DISPC_CONFIG, enable, 10, 10); -+ else /* OMAP_DSS_CHANNEL_DIGIT */ -+ REG_FLD_MOD(DISPC_CONFIG, enable, 12, 12); -+ enable_clocks(0); -+} -+ -+void dispc_set_tft_data_lines(int data_lines) -+{ -+ int code; -+ -+ switch (data_lines) { -+ case 12: -+ code = 0; -+ break; -+ case 16: -+ code = 1; -+ break; -+ case 18: -+ code = 2; -+ break; -+ case 24: -+ code = 3; -+ break; -+ default: -+ BUG(); -+ return; -+ } -+ -+ enable_clocks(1); -+ REG_FLD_MOD(DISPC_CONTROL, code, 9, 8); -+ enable_clocks(0); -+} -+ -+void dispc_set_parallel_interface_mode(enum omap_parallel_interface_mode mode) -+{ -+ u32 l; -+ int stallmode; -+ int gpout0 = 1; -+ int gpout1; -+ -+ switch (mode) { -+ case OMAP_DSS_PARALLELMODE_BYPASS: -+ stallmode = 0; -+ gpout1 = 1; -+ break; -+ -+ case OMAP_DSS_PARALLELMODE_RFBI: -+ stallmode = 1; -+ gpout1 = 0; -+ break; -+ -+ case OMAP_DSS_PARALLELMODE_DSI: -+ stallmode = 1; -+ gpout1 = 1; -+ break; -+ -+ default: -+ BUG(); -+ return; -+ } -+ -+ enable_clocks(1); -+ -+ l = dispc_read_reg(DISPC_CONTROL); -+ -+ l = FLD_MOD(l, stallmode, 11, 11); -+ l = FLD_MOD(l, gpout0, 15, 15); -+ l = FLD_MOD(l, gpout1, 16, 16); -+ -+ dispc_write_reg(DISPC_CONTROL, l); -+ -+ enable_clocks(0); -+} -+ -+static void _dispc_set_lcd_timings(int hsw, int hfp, int hbp, -+ int vsw, int vfp, int vbp) -+{ -+ u32 timing_h, timing_v; -+ -+ BUG_ON(hsw < 1 || hsw > 64); -+ BUG_ON(hfp < 1 || hfp > 256); -+ BUG_ON(hbp < 1 || hbp > 256); -+ -+ BUG_ON(vsw < 1 || vsw > 64); -+ BUG_ON(vfp < 0 || vfp > 255); -+ BUG_ON(vbp < 0 || vbp > 255); -+ -+ timing_h = FLD_VAL(hsw-1, 5, 0) | FLD_VAL(hfp-1, 15, 8) | -+ FLD_VAL(hbp-1, 27, 20); -+ -+ timing_v = FLD_VAL(vsw-1, 5, 0) | FLD_VAL(vfp, 15, 8) | -+ FLD_VAL(vbp, 27, 20); -+ -+ enable_clocks(1); -+ dispc_write_reg(DISPC_TIMING_H, timing_h); -+ dispc_write_reg(DISPC_TIMING_V, timing_v); -+ enable_clocks(0); -+} -+ -+/* change name to mode? */ -+void dispc_set_lcd_timings(struct omap_video_timings *timings) -+{ -+ unsigned xtot, ytot; -+ unsigned long ht, vt; -+ -+ _dispc_set_lcd_timings(timings->hsw, timings->hfp, timings->hbp, -+ timings->vsw, timings->vfp, timings->vbp); -+ -+ dispc_set_lcd_size(timings->x_res, timings->y_res); -+ -+ xtot = timings->x_res + timings->hfp + timings->hsw + timings->hbp; -+ ytot = timings->y_res + timings->vfp + timings->vsw + timings->vbp; -+ -+ ht = (timings->pixel_clock * 1000) / xtot; -+ vt = (timings->pixel_clock * 1000) / xtot / ytot; -+ -+ DSSDBG("xres %u yres %u\n", timings->x_res, timings->y_res); -+ DSSDBG("pck %u\n", timings->pixel_clock); -+ DSSDBG("hsw %d hfp %d hbp %d vsw %d vfp %d vbp %d\n", -+ timings->hsw, timings->hfp, timings->hbp, -+ timings->vsw, timings->vfp, timings->vbp); -+ -+ DSSDBG("hsync %luHz, vsync %luHz\n", ht, vt); -+} -+ -+void dispc_set_lcd_divisor(int lck_div, int pck_div) -+{ -+ BUG_ON(lck_div < 1); -+ BUG_ON(pck_div < 2); -+ -+ enable_clocks(1); -+ dispc_write_reg(DISPC_DIVISOR, -+ FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0)); -+ enable_clocks(0); -+} -+ -+static void dispc_get_lcd_divisor(int *lck_div, int *pck_div) -+{ -+ u32 l; -+ l = dispc_read_reg(DISPC_DIVISOR); -+ *lck_div = FLD_GET(l, 23, 16); -+ *pck_div = FLD_GET(l, 7, 0); -+} -+ -+unsigned long dispc_fclk_rate(void) -+{ -+ unsigned long r = 0; -+ -+ if (dss_get_dispc_clk_source() == 0) -+ r = dss_clk_get_rate(DSS_CLK_FCK1); -+ else -+#ifdef CONFIG_OMAP2_DSS_DSI -+ r = dsi_get_dsi1_pll_rate(); -+#else -+ BUG(); -+#endif -+ return r; -+} -+ -+unsigned long dispc_pclk_rate(void) -+{ -+ int lcd, pcd; -+ unsigned long r; -+ u32 l; -+ -+ l = dispc_read_reg(DISPC_DIVISOR); -+ -+ lcd = FLD_GET(l, 23, 16); -+ pcd = FLD_GET(l, 7, 0); -+ -+ r = dispc_fclk_rate(); -+ -+ return r / lcd / pcd; -+} -+ -+ssize_t dispc_print_clocks(char *buf, ssize_t size) -+{ -+ ssize_t l = 0; -+ int lcd, pcd; -+ -+ enable_clocks(1); -+ -+ dispc_get_lcd_divisor(&lcd, &pcd); -+ -+ l += snprintf(buf + l, size - l, "- dispc -\n"); -+ -+ l += snprintf(buf + l, size - l, "dispc fclk source = %s\n", -+ dss_get_dispc_clk_source() == 0 ? -+ "dss1_alwon_fclk" : "dsi1_pll_fclk"); -+ -+ l += snprintf(buf + l, size - l, -+ "pixel clk = %lu / %d / %d = %lu\n", -+ dispc_fclk_rate(), -+ lcd, pcd, -+ dispc_pclk_rate()); -+ -+ enable_clocks(0); -+ -+ return l; -+} -+ -+static void _dispc_set_pol_freq(int onoff, int rf, int ieo, int ipc, -+ int ihs, int ivs, int acbi, int acb) -+{ -+ u32 l = 0; -+ -+ DSSDBG("onoff %d rf %d ieo %d ipc %d ihs %d ivs %d acbi %d acb %d\n", -+ onoff, rf, ieo, ipc, ihs, ivs, acbi, acb); -+ -+ l |= FLD_VAL(onoff, 17, 17); -+ l |= FLD_VAL(rf, 16, 16); -+ l |= FLD_VAL(ieo, 15, 15); -+ l |= FLD_VAL(ipc, 14, 14); -+ l |= FLD_VAL(ihs, 13, 13); -+ l |= FLD_VAL(ivs, 12, 12); -+ l |= FLD_VAL(acbi, 11, 8); -+ l |= FLD_VAL(acb, 7, 0); -+ -+ enable_clocks(1); -+ dispc_write_reg(DISPC_POL_FREQ, l); -+ enable_clocks(0); -+} -+ -+void dispc_set_pol_freq(struct omap_panel *panel) -+{ -+ _dispc_set_pol_freq((panel->config & OMAP_DSS_LCD_ONOFF) != 0, -+ (panel->config & OMAP_DSS_LCD_RF) != 0, -+ (panel->config & OMAP_DSS_LCD_IEO) != 0, -+ (panel->config & OMAP_DSS_LCD_IPC) != 0, -+ (panel->config & OMAP_DSS_LCD_IHS) != 0, -+ (panel->config & OMAP_DSS_LCD_IVS) != 0, -+ panel->acbi, panel->acb); -+} -+ -+void find_lck_pck_divs(int is_tft, unsigned long req_pck, unsigned long fck, -+ int *lck_div, int *pck_div) -+{ -+ int pcd_min = is_tft ? 2 : 3; -+ unsigned long best_pck; -+ int best_ld, cur_ld; -+ int best_pd, cur_pd; -+ -+ best_pck = 0; -+ best_ld = 0; -+ best_pd = 0; -+ -+ for (cur_ld = 1; cur_ld <= 255; ++cur_ld) { -+ unsigned long lck = fck / cur_ld; -+ -+ for (cur_pd = pcd_min; cur_pd <= 255; ++cur_pd) { -+ unsigned long pck = lck / cur_pd; -+ long old_delta = abs(best_pck - req_pck); -+ long new_delta = abs(pck - req_pck); -+ -+ if (best_pck == 0 || new_delta < old_delta) { -+ best_pck = pck; -+ best_ld = cur_ld; -+ best_pd = cur_pd; -+ -+ if (pck == req_pck) -+ goto found; -+ } -+ -+ if (pck < req_pck) -+ break; -+ } -+ -+ if (lck / pcd_min < req_pck) -+ break; -+ } -+ -+found: -+ *lck_div = best_ld; -+ *pck_div = best_pd; -+} -+ -+int dispc_calc_clock_div(int is_tft, unsigned long req_pck, -+ struct dispc_clock_info *cinfo) -+{ -+ unsigned long prate; -+ struct dispc_clock_info cur, best; -+ int match = 0; -+ int min_fck_per_pck; -+ -+ if (cpu_is_omap34xx()) -+ prate = clk_get_rate(clk_get_parent(dispc.dpll4_m4_ck)); -+ else -+ prate = 0; -+ -+ if (req_pck == dispc.cache_req_pck && -+ ((cpu_is_omap34xx() && prate == dispc.cache_prate) || -+ dispc.cache_cinfo.fck == dss_clk_get_rate(DSS_CLK_FCK1))) { -+ DSSDBG("dispc clock info found from cache.\n"); -+ *cinfo = dispc.cache_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(&cur, 0, sizeof(cur)); -+ memset(&best, 0, sizeof(best)); -+ -+ if (cpu_is_omap24xx()) { -+ /* XXX can we change the clock on omap2? */ -+ cur.fck = dss_clk_get_rate(DSS_CLK_FCK1); -+ cur.fck_div = 1; -+ -+ match = 1; -+ -+ find_lck_pck_divs(is_tft, req_pck, cur.fck, -+ &cur.lck_div, &cur.pck_div); -+ -+ cur.lck = cur.fck / cur.lck_div; -+ cur.pck = cur.lck / cur.pck_div; -+ -+ best = cur; -+ -+ goto found; -+ } else if (cpu_is_omap34xx()) { -+ for (cur.fck_div = 16; cur.fck_div > 0; --cur.fck_div) { -+ cur.fck = prate / cur.fck_div * 2; -+ -+ if (cur.fck > DISPC_MAX_FCK) -+ continue; -+ -+ if (min_fck_per_pck && -+ cur.fck < req_pck * min_fck_per_pck) -+ continue; -+ -+ match = 1; -+ -+ find_lck_pck_divs(is_tft, req_pck, cur.fck, -+ &cur.lck_div, &cur.pck_div); -+ -+ cur.lck = cur.fck / cur.lck_div; -+ cur.pck = cur.lck / cur.pck_div; -+ -+ if (abs(cur.pck - req_pck) < abs(best.pck - req_pck)) { -+ best = cur; -+ -+ if (cur.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 (cinfo) -+ *cinfo = best; -+ -+ dispc.cache_req_pck = req_pck; -+ dispc.cache_prate = prate; -+ dispc.cache_cinfo = best; -+ -+ return 0; -+} -+ -+int dispc_set_clock_div(struct dispc_clock_info *cinfo) -+{ -+ unsigned long prate; -+ int r; -+ -+ if (cpu_is_omap34xx()) { -+ prate = clk_get_rate(clk_get_parent(dispc.dpll4_m4_ck)); -+ DSSDBG("dpll4_m4 = %ld\n", prate); -+ } -+ -+ DSSDBG("fck = %ld (%d)\n", cinfo->fck, cinfo->fck_div); -+ DSSDBG("lck = %ld (%d)\n", cinfo->lck, cinfo->lck_div); -+ DSSDBG("pck = %ld (%d)\n", cinfo->pck, cinfo->pck_div); -+ -+ if (cpu_is_omap34xx()) { -+ r = clk_set_rate(dispc.dpll4_m4_ck, prate / cinfo->fck_div); -+ if (r) -+ return r; -+ } -+ -+ dispc_set_lcd_divisor(cinfo->lck_div, cinfo->pck_div); -+ -+ return 0; -+} -+ -+int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask) -+{ -+ int i; -+ int ret = -EBUSY; -+ unsigned long flags; -+ u32 new_mask = 0; -+ -+ if (isr == NULL) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&dispc.irq_lock, flags); -+ -+ for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { -+ if (registered_isr[i].isr == isr) { -+ ret = -EINVAL; -+ break; -+ } -+ -+ if (registered_isr[i].isr != NULL) -+ continue; -+ -+ registered_isr[i].isr = isr; -+ registered_isr[i].arg = arg; -+ registered_isr[i].mask = mask; -+ -+ enable_clocks(1); -+ new_mask = dispc_read_reg(DISPC_IRQENABLE); -+ new_mask |= mask; -+ dispc_write_reg(DISPC_IRQENABLE, new_mask); -+ enable_clocks(0); -+ -+ ret = 0; -+ break; -+ } -+ -+ spin_unlock_irqrestore(&dispc.irq_lock, flags); -+ -+ return ret; -+} -+EXPORT_SYMBOL(omap_dispc_register_isr); -+ -+int omap_dispc_unregister_isr(omap_dispc_isr_t isr) -+{ -+ int i, j; -+ unsigned long flags; -+ u32 new_mask = DISPC_IRQ_MASK_ERROR; -+ int ret = -EINVAL; -+ -+ spin_lock_irqsave(&dispc.irq_lock, flags); -+ -+ for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { -+ if (registered_isr[i].isr != isr) -+ continue; -+ -+ registered_isr[i].isr = NULL; -+ registered_isr[i].arg = NULL; -+ registered_isr[i].mask = 0; -+ -+ for (j = 0; j < DISPC_MAX_NR_ISRS; j++) -+ new_mask |= registered_isr[j].mask; -+ -+ enable_clocks(1); -+ dispc_write_reg(DISPC_IRQENABLE, new_mask); -+ enable_clocks(0); -+ -+ ret = 0; -+ break; -+ } -+ -+ spin_unlock_irqrestore(&dispc.irq_lock, flags); -+ -+ return ret; -+} -+EXPORT_SYMBOL(omap_dispc_unregister_isr); -+ -+#ifdef DEBUG -+static void print_irq_status(u32 status) -+{ -+ if ((status & DISPC_IRQ_MASK_ERROR) == 0) -+ return; -+ -+ printk(KERN_DEBUG "DISPC IRQ: 0x%x: ", status); -+ -+#define PIS(x) \ -+ if (status & DISPC_IRQ_##x) \ -+ printk(#x " "); -+ PIS(GFX_FIFO_UNDERFLOW); -+ PIS(OCP_ERR); -+ PIS(VID1_FIFO_UNDERFLOW); -+ PIS(VID2_FIFO_UNDERFLOW); -+ PIS(SYNC_LOST); -+ PIS(SYNC_LOST_DIGIT); -+#undef PIS -+ -+ printk("\n"); -+} -+#endif -+ -+/* Called from dss.c. Note that we don't touch clocks here, -+ * but we presume they are on because we got an IRQ. However, -+ * an irq handler may turn the clocks off, so we may not have -+ * clock later in the function. */ -+void dispc_irq_handler(void) -+{ -+ int i; -+ u32 irqstatus = dispc_read_reg(DISPC_IRQSTATUS); -+ static int errors; -+ u32 handledirqs = 0; -+ -+#ifdef DEBUG -+ if (dss_debug) -+ print_irq_status(irqstatus); -+#endif -+ /* Ack the interrupt. Do it here before clocks are possibly turned -+ * off */ -+ dispc_write_reg(DISPC_IRQSTATUS, irqstatus); -+ -+ for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { -+ if (!registered_isr[i].isr) -+ continue; -+ if (registered_isr[i].mask & irqstatus) { -+ registered_isr[i].isr(registered_isr[i].arg, -+ irqstatus); -+ handledirqs |= registered_isr[i].mask; -+ } -+ } -+ -+ if (irqstatus & ~handledirqs & DISPC_IRQ_MASK_ERROR) { -+ if (printk_ratelimit()) { -+ DSSERR("dispc irq error status %04x\n", -+ irqstatus); -+ } -+ if (errors++ > 100) { -+ DSSERR("Excessive DISPC errors\n" -+ "Turning off lcd and digit\n"); -+ dispc_enable_lcd_out(0); -+ dispc_enable_digit_out(0); -+ } -+ } -+ -+} -+ -+#ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC -+void dispc_fake_vsync_irq(void) -+{ -+ u32 irqstatus = DISPC_IRQ_VSYNC; -+ int i; -+ -+ for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { -+ if (!registered_isr[i].isr) -+ continue; -+ if (registered_isr[i].mask & irqstatus) -+ registered_isr[i].isr(registered_isr[i].arg, -+ irqstatus); -+ } -+} -+#endif -+ -+static void _omap_dispc_initialize_irq(void) -+{ -+ memset(registered_isr, 0, sizeof(registered_isr)); -+ -+ /* there's SYNC_LOST_DIGIT waiting after enabling the DSS, -+ * so clear it */ -+ dispc_write_reg(DISPC_IRQSTATUS, -+ dispc_read_reg(DISPC_IRQSTATUS)); -+ -+ /* We'll handle these always */ -+ dispc_write_reg(DISPC_IRQENABLE, DISPC_IRQ_MASK_ERROR); -+} -+ -+static void _omap_dispc_initial_config(void) -+{ -+ u32 l; -+ -+ l = dispc_read_reg(DISPC_SYSCONFIG); -+ l = FLD_MOD(l, 2, 13, 12); /* MIDLEMODE: smart standby */ -+ l = FLD_MOD(l, 2, 4, 3); /* SIDLEMODE: smart idle */ -+ l = FLD_MOD(l, 1, 2, 2); /* ENWAKEUP */ -+ l = FLD_MOD(l, 1, 0, 0); /* AUTOIDLE */ -+ dispc_write_reg(DISPC_SYSCONFIG, l); -+ -+ /* FUNCGATED */ -+ REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9); -+ -+ /* L3 firewall setting: enable access to OCM RAM */ -+ __raw_writel(0x402000b0, IO_ADDRESS(0x680050a0)); -+ -+ _dispc_setup_color_conv_coef(); -+ -+ dispc_set_loadmode(OMAP_DSS_LOAD_FRAME_ONLY); -+ -+ /* Set logic clock to fck, pixel clock to fck/2 for now */ -+ dispc_set_lcd_divisor(1, 2); -+} -+ -+int dispc_init(void) -+{ -+ u32 rev; -+ -+ spin_lock_init(&dispc.irq_lock); -+ -+ dispc.base = ioremap(DISPC_BASE, DISPC_SZ_REGS); -+ if (!dispc.base) { -+ DSSERR("can't ioremap DISPC\n"); -+ return -ENOMEM; -+ } -+ -+ if (cpu_is_omap34xx()) { -+ dispc.dpll4_m4_ck = clk_get(NULL, "dpll4_m4_ck"); -+ if (IS_ERR(dispc.dpll4_m4_ck)) { -+ DSSERR("Failed to get dpll4_m4_ck\n"); -+ return -ENODEV; -+ } -+ } -+ -+ enable_clocks(1); -+ -+ _omap_dispc_initial_config(); -+ -+ _omap_dispc_initialize_irq(); -+ -+ dispc_save_context(); -+ -+ rev = dispc_read_reg(DISPC_REVISION); -+ printk(KERN_INFO "OMAP DISPC rev %d.%d\n", -+ FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); -+ -+ enable_clocks(0); -+ -+ return 0; -+} -+ -+void dispc_exit(void) -+{ -+ if (cpu_is_omap34xx()) -+ clk_put(dispc.dpll4_m4_ck); -+ iounmap(dispc.base); -+} -+ -+int dispc_enable_plane(enum omap_plane plane, int enable) -+{ -+ DSSDBG("dispc_enable_plane %d, %d\n", plane, enable); -+ -+ enable_clocks(1); -+ _dispc_enable_plane(plane, enable); -+ enable_clocks(0); -+ -+ return 0; -+} -+ -+int dispc_setup_plane(enum omap_plane plane, enum omap_channel channel_out, -+ u32 paddr, int screen_width, -+ int pos_x, int pos_y, -+ int width, int height, -+ int out_width, int out_height, -+ enum omap_color_mode color_mode, -+ int ilace) -+{ -+ int r = 0; -+ -+ DSSDBG("dispc_setup_plane %d, %x, sw %d, %d,%d, %dx%d -> " -+ "%dx%d, (ilace %d)\n", -+ plane, paddr, screen_width, pos_x, pos_y, -+ width, height, -+ out_width, out_height, -+ ilace); -+ -+ enable_clocks(1); -+ -+ r = _dispc_setup_plane(plane, channel_out, -+ paddr, screen_width, -+ pos_x, pos_y, -+ width, height, -+ out_width, out_height, -+ color_mode, ilace); -+ -+ enable_clocks(0); -+ -+ return r; -+} -+ -+static int dispc_is_intersecting(int x1, int y1, int w1, int h1, -+ int x2, int y2, int w2, int h2) -+{ -+ if (x1 >= (x2+w2)) -+ return 0; -+ -+ if ((x1+w1) <= x2) -+ return 0; -+ -+ if (y1 >= (y2+h2)) -+ return 0; -+ -+ if ((y1+h1) <= y2) -+ return 0; -+ -+ return 1; -+} -+ -+static int dispc_is_overlay_scaled(struct omap_overlay_info *pi) -+{ -+ if (pi->width != pi->out_width) -+ return 1; -+ -+ if (pi->height != pi->out_height) -+ return 1; -+ -+ return 0; -+} -+ -+/* returns the area that needs updating */ -+void dispc_setup_partial_planes(struct omap_display *display, -+ int *xi, int *yi, int *wi, int *hi) -+{ -+ struct omap_overlay_manager *mgr; -+ int i; -+ -+ int x, y, w, h; -+ -+ x = *xi; -+ y = *yi; -+ w = *wi; -+ h = *hi; -+ -+ DSSDBG("dispc_setup_partial_planes %d,%d %dx%d\n", -+ *xi, *yi, *wi, *hi); -+ -+ -+ mgr = display->manager; -+ -+ if (!mgr) { -+ DSSDBG("no manager\n"); -+ return; -+ } -+ -+ for (i = 0; i < mgr->num_overlays; i++) { -+ struct omap_overlay *ovl; -+ struct omap_overlay_info *pi; -+ ovl = &mgr->overlays[i]; -+ -+ if (ovl->manager != mgr) -+ continue; -+ -+ if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) -+ continue; -+ -+ pi = &ovl->info; -+ -+ if (!pi->enabled) -+ continue; -+ /* -+ * If the plane is intersecting and scaled, we -+ * enlarge the update region to accomodate the -+ * whole area -+ */ -+ -+ if (dispc_is_intersecting(x, y, w, h, -+ pi->pos_x, pi->pos_y, -+ pi->out_width, pi->out_height)) { -+ if (dispc_is_overlay_scaled(pi)) { -+ -+ int x1, y1, x2, y2; -+ -+ if (x > pi->pos_x) -+ x1 = pi->pos_x; -+ else -+ x1 = x; -+ -+ if (y > pi->pos_y) -+ y1 = pi->pos_y; -+ else -+ y1 = y; -+ -+ if ((x + w) < (pi->pos_x + pi->out_width)) -+ x2 = pi->pos_x + pi->out_width; -+ else -+ x2 = x + w; -+ -+ if ((y + h) < (pi->pos_y + pi->out_height)) -+ y2 = pi->pos_y + pi->out_height; -+ else -+ y2 = y + h; -+ -+ x = x1; -+ y = y1; -+ w = x2 - x1; -+ h = y2 - y1; -+ -+ DSSDBG("Update area after enlarge due to " -+ "scaling %d, %d %dx%d\n", -+ x, y, w, h); -+ } -+ } -+ } -+ -+ for (i = 0; i < mgr->num_overlays; i++) { -+ struct omap_overlay *ovl = &mgr->overlays[i]; -+ struct omap_overlay_info *pi = &ovl->info; -+ -+ int px = pi->pos_x; -+ int py = pi->pos_y; -+ int pw = pi->width; -+ int ph = pi->height; -+ int pow = pi->out_width; -+ int poh = pi->out_height; -+ u32 pa = pi->paddr; -+ int psw = pi->screen_width; -+ int bpp; -+ -+ if (ovl->manager != mgr) -+ continue; -+ -+ /* -+ * If plane is not enabled or the update region -+ * does not intersect with the plane in question, -+ * we really disable the plane from hardware -+ */ -+ -+ if (!pi->enabled || -+ !dispc_is_intersecting(x, y, w, h, -+ px, py, pow, poh)) { -+ dispc_enable_plane(ovl->id, 0); -+ continue; -+ } -+ -+ switch (pi->color_mode) { -+ case OMAP_DSS_COLOR_RGB16: -+ bpp = 16; -+ break; -+ -+ case OMAP_DSS_COLOR_RGB24P: -+ bpp = 24; -+ break; -+ -+ case OMAP_DSS_COLOR_RGB24U: -+ bpp = 32; -+ break; -+ -+ case OMAP_DSS_COLOR_YUV2: -+ case OMAP_DSS_COLOR_UYVY: -+ bpp = 16; -+ break; -+ -+ default: -+ BUG(); -+ return; -+ } -+ -+ if (x > pi->pos_x) { -+ px = 0; -+ pw -= (x - pi->pos_x); -+ pa += (x - pi->pos_x) * bpp / 8; -+ } else { -+ px = pi->pos_x - x; -+ } -+ -+ if (y > pi->pos_y) { -+ py = 0; -+ ph -= (y - pi->pos_y); -+ pa += (y - pi->pos_y) * psw * bpp / 8; -+ } else { -+ py = pi->pos_y - y; -+ } -+ -+ if (w < (px+pw)) -+ pw -= (px+pw) - (w); -+ -+ if (h < (py+ph)) -+ ph -= (py+ph) - (h); -+ -+ /* Can't scale the GFX plane */ -+ if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0 || -+ dispc_is_overlay_scaled(pi) == 0) { -+ pow = pw; -+ poh = ph; -+ } -+ -+ DSSDBG("calc plane %d, %x, sw %d, %d,%d, %dx%d -> %dx%d\n", -+ ovl->id, pa, psw, px, py, pw, ph, pow, poh); -+ -+ dispc_setup_plane(ovl->id, mgr->id, -+ pa, psw, -+ px, py, -+ pw, ph, -+ pow, poh, -+ pi->color_mode, 0); -+ -+ dispc_enable_plane(ovl->id, 1); -+ } -+ -+ *xi = x; -+ *yi = y; -+ *wi = w; -+ *hi = h; -+ -+} -+ -diff --git a/arch/arm/plat-omap/dss/display.c b/arch/arm/plat-omap/dss/display.c -new file mode 100644 -index 0000000..e3ff778 ---- /dev/null -+++ b/arch/arm/plat-omap/dss/display.c -@@ -0,0 +1,787 @@ -+/* -+ * linux/arch/arm/plat-omap/dss/display.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/>. -+ */ -+ -+#define DSS_SUBSYS_NAME "DISPLAY" -+ -+#include <linux/kernel.h> -+#include <linux/io.h> -+#include <linux/device.h> -+#include <linux/err.h> -+#include <linux/sysfs.h> -+#include <linux/clk.h> -+ -+#include <mach/display.h> -+#include <mach/clock.h> -+#include "dss.h" -+ -+#define DSS_MAX_DISPLAYS 8 -+ -+static int num_displays; -+static struct omap_display displays[DSS_MAX_DISPLAYS]; -+ -+static ssize_t show_clk(struct device *dev, struct device_attribute *attr, -+ char *buf) -+{ -+ ssize_t l, size = PAGE_SIZE; -+ -+ l = 0; -+ -+ l += dss_print_clocks(buf + l, size - l); -+ -+ l += dispc_print_clocks(buf + l, size - l); -+#ifdef CONFIG_OMAP2_DSS_DSI -+ l += dsi_print_clocks(buf + l, size - l); -+#endif -+ return l; -+} -+ -+static DEVICE_ATTR(clk, S_IRUGO, show_clk, NULL); -+ -+int initialize_sysfs(struct device *dev) -+{ -+ int r; -+ -+ r = device_create_file(dev, &dev_attr_clk); -+ if (r) -+ DSSERR("failed to create sysfs clk file\n"); -+ -+ return r; -+} -+ -+void uninitialize_sysfs(struct device *dev) -+{ -+ device_remove_file(dev, &dev_attr_clk); -+} -+ -+void initialize_displays(struct omap_dss_platform_data *pdata) -+{ -+ int i; -+ -+ num_displays = 0; -+ -+ BUG_ON(pdata->num_displays > DSS_MAX_DISPLAYS); -+ -+ for (i = 0; i < pdata->num_displays; ++i) { -+ struct omap_display *display = &displays[i]; -+ -+ /*atomic_set(&display->ref_count, 0);*/ -+ display->ref_count = 0; -+ -+ display->hw_config = *pdata->displays[i]; -+ display->type = pdata->displays[i]->type; -+ display->name = pdata->displays[i]->name; -+ -+ switch (display->type) { -+ -+ case OMAP_DISPLAY_TYPE_DPI: -+ dpi_init_display(display); -+ break; -+#ifdef CONFIG_OMAP2_DSS_RFBI -+ case OMAP_DISPLAY_TYPE_DBI: -+ rfbi_init_display(display); -+ break; -+#endif -+#ifdef CONFIG_OMAP2_DSS_VENC -+ case OMAP_DISPLAY_TYPE_VENC: -+ venc_init_display(display); -+ break; -+#endif -+#ifdef CONFIG_OMAP2_DSS_SDI -+ case OMAP_DISPLAY_TYPE_SDI: -+ sdi_init_display(display); -+ break; -+#endif -+#ifdef CONFIG_OMAP2_DSS_DSI -+ case OMAP_DISPLAY_TYPE_DSI: -+ dsi_init_display(display); -+ break; -+#endif -+ -+ default: -+ DSSERR("Support for display '%s' not compiled in.\n", -+ display->name); -+ continue; -+ } -+ -+ num_displays++; -+ } -+} -+ -+static int check_overlay(struct omap_overlay *ovl, -+ struct omap_display *display) -+{ -+ struct omap_overlay_info *info; -+ int outw, outh; -+ -+ if (!display) -+ return 0; -+ -+ if (!ovl->info.enabled) -+ return 0; -+ -+ info = &ovl->info; -+ -+ 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 (display->panel->timings.x_res < info->pos_x + outw) -+ return -EINVAL; -+ -+ if (display->panel->timings.y_res < info->pos_y + outh) -+ return -EINVAL; -+ -+ return 0; -+} -+ -+ -+static int omap_dss_set_manager(struct omap_overlay *ovl, -+ struct omap_overlay_manager *mgr) -+{ -+ int r; -+ -+ if (ovl->manager) { -+ DSSERR("overlay '%s' already has a manager '%s'\n", -+ ovl->name, ovl->manager->name); -+ } -+ -+ r = check_overlay(ovl, mgr->display); -+ if (r) -+ return r; -+ -+ ovl->manager = mgr; -+ -+ return 0; -+} -+ -+static int omap_dss_unset_manager(struct omap_overlay *ovl) -+{ -+ if (!ovl->manager) { -+ DSSERR("failed to detach overlay: manager not set\n"); -+ return -EINVAL; -+ } -+ -+ ovl->manager = NULL; -+ -+ return 0; -+} -+ -+static int omap_dss_set_display(struct omap_overlay_manager *mgr, -+ struct omap_display *display) -+{ -+ int i; -+ int r; -+ -+ if (display->manager) { -+ DSSERR("display '%s' already has a manager '%s'\n", -+ display->name, display->manager->name); -+ return -EINVAL; -+ } -+ -+ if ((mgr->supported_displays & display->type) == 0) { -+ DSSERR("display '%s' does not support manager '%s'\n", -+ display->name, mgr->name); -+ return -EINVAL; -+ } -+ -+ for (i = 0; i < mgr->num_overlays; i++) { -+ struct omap_overlay *ovl = &mgr->overlays[i]; -+ -+ if (ovl->manager != mgr || !ovl->info.enabled) -+ continue; -+ -+ r = check_overlay(ovl, display); -+ if (r) -+ return r; -+ } -+ -+ display->manager = mgr; -+ mgr->display = display; -+ -+ return 0; -+} -+ -+static int omap_dss_unset_display(struct omap_overlay_manager *mgr) -+{ -+ if (!mgr->display) { -+ DSSERR("failed to unset display, display not set.\n"); -+ return -EINVAL; -+ } -+ -+ mgr->display->manager = NULL; -+ mgr->display = NULL; -+ -+ return 0; -+} -+ -+static int omap_dss_setup_overlay_input(struct omap_overlay *ovl, -+ u32 paddr, void *vaddr, int screen_width, -+ int width, int height, -+ enum omap_color_mode color_mode) -+{ -+ int r; -+ struct omap_overlay_info old_info; -+ -+ if ((ovl->supported_modes & color_mode) == 0) { -+ DSSERR("overlay doesn't support mode %d\n", color_mode); -+ return -EINVAL; -+ } -+ -+ old_info = ovl->info; -+ -+ ovl->info.paddr = paddr; -+ ovl->info.vaddr = vaddr; -+ ovl->info.screen_width = screen_width; -+ -+ ovl->info.width = width; -+ ovl->info.height = height; -+ ovl->info.color_mode = color_mode; -+ -+ if (ovl->manager) { -+ r = check_overlay(ovl, ovl->manager->display); -+ if (r) { -+ ovl->info = old_info; -+ return r; -+ } -+ } -+ -+ return 0; -+} -+ -+static int omap_dss_setup_overlay_output(struct omap_overlay *ovl, -+ int pos_x, int pos_y, -+ int out_width, int out_height) -+{ -+ int r; -+ struct omap_overlay_info old_info; -+ -+ old_info = ovl->info; -+ -+ ovl->info.pos_x = pos_x; -+ ovl->info.pos_y = pos_y; -+ ovl->info.out_width = out_width; -+ ovl->info.out_height = out_height; -+ -+ if (ovl->manager) { -+ r = check_overlay(ovl, ovl->manager->display); -+ if (r) { -+ ovl->info = old_info; -+ return r; -+ } -+ } -+ -+ return 0; -+} -+ -+static int omap_dss_enable_overlay(struct omap_overlay *ovl, int enable) -+{ -+ struct omap_overlay_info old_info; -+ int r; -+ -+ old_info = ovl->info; -+ -+ ovl->info.enabled = enable ? 1 : 0; -+ -+ if (ovl->manager) { -+ r = check_overlay(ovl, ovl->manager->display); -+ if (r) { -+ ovl->info = old_info; -+ return r; -+ } -+ } -+ -+ return 0; -+} -+ -+ -+static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) -+{ -+ int i; -+ int r = 0; -+ -+ DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name); -+ -+ if (!mgr->display) { -+ DSSDBG("no display, aborting apply\n"); -+ return 0; -+ } -+ -+ /* on a manual update display update() handles configuring -+ * planes */ -+ if (mgr->display->get_update_mode) { -+ enum omap_dss_update_mode mode; -+ mode = mgr->display->get_update_mode(mgr->display); -+ if (mode == OMAP_DSS_UPDATE_MANUAL) -+ return 0; -+ } -+ -+ dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); -+ -+ for (i = 0; i < mgr->num_overlays; i++) { -+ int ilace = 0; -+ int outw, outh; -+ -+ struct omap_overlay *ovl = &mgr->overlays[i]; -+ -+ if (!ovl->manager) { -+ dispc_enable_plane(ovl->id, 0); -+ continue; -+ } -+ -+ if (ovl->manager != mgr) -+ continue; -+ -+ if (!ovl->info.enabled) { -+ dispc_enable_plane(ovl->id, 0); -+ continue; -+ } -+ -+ if (mgr->display->type == OMAP_DISPLAY_TYPE_VENC) -+ ilace = 1; -+ -+ if (ovl->info.out_width == 0) -+ outw = ovl->info.width; -+ else -+ outw = ovl->info.out_width; -+ -+ if (ovl->info.out_height == 0) -+ outh = ovl->info.height; -+ else -+ outh = ovl->info.out_height; -+ -+ r = dispc_setup_plane(ovl->id, ovl->manager->id, -+ ovl->info.paddr, -+ ovl->info.screen_width, -+ ovl->info.pos_x, -+ ovl->info.pos_y, -+ ovl->info.width, -+ ovl->info.height, -+ outw, -+ outh, -+ ovl->info.color_mode, -+ ilace); -+ -+ if (r) { -+ DSSERR("dispc_setup_plane failed\n"); -+ goto exit; -+ } -+ -+ dispc_enable_plane(ovl->id, 1); -+ } -+ -+ dispc_go(mgr->id); -+ -+exit: -+ dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); -+ -+ return r; -+} -+ -+static struct omap_overlay dispc_overlays[] = { -+ { -+ .name = "gfx", -+ .id = OMAP_DSS_GFX, -+ .set_manager = &omap_dss_set_manager, -+ .unset_manager = &omap_dss_unset_manager, -+ .setup_input = &omap_dss_setup_overlay_input, -+ .setup_output = &omap_dss_setup_overlay_output, -+ .enable = &omap_dss_enable_overlay, -+ .supported_modes = OMAP_DSS_COLOR_GFX_OMAP3, -+ }, -+ { -+ .name = "vid1", -+ .id = OMAP_DSS_VIDEO1, -+ .set_manager = &omap_dss_set_manager, -+ .unset_manager = &omap_dss_unset_manager, -+ .setup_input = &omap_dss_setup_overlay_input, -+ .setup_output = &omap_dss_setup_overlay_output, -+ .enable = &omap_dss_enable_overlay, -+ .supported_modes = OMAP_DSS_COLOR_VID_OMAP3, -+ .caps = OMAP_DSS_OVL_CAP_SCALE, -+ }, -+ { -+ .name = "vid2", -+ .id = OMAP_DSS_VIDEO2, -+ .set_manager = &omap_dss_set_manager, -+ .unset_manager = &omap_dss_unset_manager, -+ .setup_input = &omap_dss_setup_overlay_input, -+ .setup_output = &omap_dss_setup_overlay_output, -+ .enable = &omap_dss_enable_overlay, -+ .supported_modes = OMAP_DSS_COLOR_VID_OMAP3, -+ .caps = OMAP_DSS_OVL_CAP_SCALE, -+ }, -+}; -+ -+static struct omap_overlay_manager dispc_overlay_managers[] = -+{ -+ [OMAP_DSS_OVL_MGR_LCD] = { -+ .name = "lcd", -+ .id = OMAP_DSS_CHANNEL_LCD, -+ .num_overlays = 3, -+ .overlays = dispc_overlays, -+ .set_display = &omap_dss_set_display, -+ .unset_display = &omap_dss_unset_display, -+ .apply = &omap_dss_mgr_apply, -+ .caps = OMAP_DSS_OVL_MGR_CAP_DISPC, -+ .supported_displays = -+ OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI | -+ OMAP_DISPLAY_TYPE_SDI | OMAP_DISPLAY_TYPE_DSI, -+ }, -+ [OMAP_DSS_OVL_MGR_TV] = { -+ .name = "tv", -+ .id = OMAP_DSS_CHANNEL_DIGIT, -+ .num_overlays = 3, -+ .overlays = dispc_overlays, -+ .set_display = &omap_dss_set_display, -+ .unset_display = &omap_dss_unset_display, -+ .apply = &omap_dss_mgr_apply, -+ .caps = OMAP_DSS_OVL_MGR_CAP_DISPC, -+ .supported_displays = OMAP_DISPLAY_TYPE_VENC, -+ }, -+}; -+ -+static int num_overlays = 3; -+ -+static struct omap_overlay *omap_dss_overlays[10] = { -+ &dispc_overlays[0], -+ &dispc_overlays[1], -+ &dispc_overlays[2], -+}; -+ -+static int num_overlay_managers = 2; -+ -+static struct omap_overlay_manager *omap_dss_overlay_managers[10] = { -+ &dispc_overlay_managers[0], -+ &dispc_overlay_managers[1], -+}; -+ -+ -+static void omap_dss_add_overlay(struct omap_overlay *overlay) -+{ -+ int i = num_overlays++; -+ -+ omap_dss_overlays[i] = overlay; -+} -+ -+static void omap_dss_add_overlay_manager(struct omap_overlay_manager *manager) -+{ -+ int i = num_overlay_managers++; -+ omap_dss_overlay_managers[i] = manager; -+} -+ -+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) -+{ -+ BUG_ON(num >= num_overlays); -+ return omap_dss_overlays[num]; -+} -+EXPORT_SYMBOL(omap_dss_get_overlay); -+ -+int omap_dss_get_num_overlay_managers(void) -+{ -+ return num_overlay_managers; -+} -+EXPORT_SYMBOL(omap_dss_get_num_overlay_managers); -+ -+struct omap_overlay_manager *omap_dss_get_overlay_manager(int num) -+{ -+ BUG_ON(num >= num_overlay_managers); -+ return omap_dss_overlay_managers[num]; -+} -+EXPORT_SYMBOL(omap_dss_get_overlay_manager); -+ -+static int ovl_mgr_apply_l4(struct omap_overlay_manager *mgr) -+{ -+ DSSDBG("omap_dss_mgr_apply_l4(%s)\n", mgr->name); -+ -+ return 0; -+} -+ -+void initialize_overlays(const char *def_disp_name) -+{ -+ int i; -+ struct omap_overlay_manager *lcd_mgr; -+ struct omap_overlay_manager *tv_mgr; -+ struct omap_overlay_manager *def_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 (def_disp_name) { -+ for (i = 0; i < num_displays; i++) { -+ struct omap_display *display = &displays[i]; -+ -+ if (strcmp(display->name, def_disp_name) == 0) { -+ if (display->type != OMAP_DISPLAY_TYPE_VENC) { -+ omap_dss_set_display(lcd_mgr, display); -+ def_mgr = lcd_mgr; -+ } else { -+ omap_dss_set_display(tv_mgr, display); -+ def_mgr = tv_mgr; -+ } -+ -+ break; -+ } -+ } -+ -+ if (!def_mgr) -+ DSSWARN("default display %s not found\n", -+ def_disp_name); -+ } -+ -+ if (def_mgr != lcd_mgr) { -+ /* connect lcd manager to first non-VENC display found */ -+ for (i = 0; i < num_displays; i++) { -+ struct omap_display *display = &displays[i]; -+ if (display->type != OMAP_DISPLAY_TYPE_VENC) { -+ omap_dss_set_display(lcd_mgr, display); -+ -+ if (!def_mgr) -+ def_mgr = lcd_mgr; -+ -+ break; -+ } -+ } -+ } -+ -+ if (def_mgr != tv_mgr) { -+ /* connect tv manager to first VENC display found */ -+ for (i = 0; i < num_displays; i++) { -+ struct omap_display *display = &displays[i]; -+ if (display->type == OMAP_DISPLAY_TYPE_VENC) { -+ omap_dss_set_display(tv_mgr, display); -+ -+ if (!def_mgr) -+ def_mgr = tv_mgr; -+ -+ break; -+ } -+ } -+ } -+ -+ /* connect all dispc overlays to def_mgr */ -+ if (def_mgr) { -+ for (i = 0; i < 3; i++) { -+ struct omap_overlay *ovl; -+ ovl = omap_dss_get_overlay(i); -+ omap_dss_set_manager(ovl, def_mgr); -+ } -+ } -+ -+ /* setup L4 overlay as an example */ -+ { -+ static struct omap_overlay ovl = { -+ .name = "l4-ovl", -+ .supported_modes = OMAP_DSS_COLOR_RGB24U, -+ .set_manager = &omap_dss_set_manager, -+ .unset_manager = &omap_dss_unset_manager, -+ .setup_input = &omap_dss_setup_overlay_input, -+ .setup_output = &omap_dss_setup_overlay_output, -+ .enable = &omap_dss_enable_overlay, -+ }; -+ -+ static struct omap_overlay_manager mgr = { -+ .name = "l4", -+ .num_overlays = 1, -+ .overlays = &ovl, -+ .set_display = &omap_dss_set_display, -+ .unset_display = &omap_dss_unset_display, -+ .apply = &ovl_mgr_apply_l4, -+ .supported_displays = -+ OMAP_DISPLAY_TYPE_DBI | OMAP_DISPLAY_TYPE_DSI, -+ }; -+ -+ omap_dss_add_overlay(&ovl); -+ omap_dss_add_overlay_manager(&mgr); -+ omap_dss_set_manager(&ovl, &mgr); -+ } -+ -+} -+ -+ -+int omap_dss_get_num_displays(void) -+{ -+ return num_displays; -+} -+EXPORT_SYMBOL(omap_dss_get_num_displays); -+ -+struct omap_display *omap_dss_get_display(int no) -+{ -+ struct omap_display *display; -+ -+ if (no >= num_displays) -+ return NULL; -+ -+ display = &displays[no]; -+ -+ switch (display->type) { -+ case OMAP_DISPLAY_TYPE_VENC: -+ break; -+ -+ case OMAP_DISPLAY_TYPE_DPI: -+ case OMAP_DISPLAY_TYPE_SDI: -+ if (display->panel == NULL) -+ return NULL; -+ break; -+ -+ case OMAP_DISPLAY_TYPE_DBI: -+ case OMAP_DISPLAY_TYPE_DSI: -+ if (display->panel == NULL || display->ctrl == NULL) -+ return NULL; -+ break; -+ -+ default: -+ return NULL; -+ } -+ -+ if (display->panel) { -+ if (!try_module_get(display->panel->owner)) -+ goto err0; -+ -+ if (display->panel->init) -+ if (display->panel->init(display) != 0) -+ goto err1; -+ } -+ -+ if (display->ctrl) { -+ if (!try_module_get(display->ctrl->owner)) -+ goto err2; -+ -+ if (display->ctrl->init) -+ if (display->ctrl->init(display) != 0) -+ goto err3; -+ } -+ -+ display->ref_count++; -+ /* -+ if (atomic_cmpxchg(&display->ref_count, 0, 1) != 0) -+ return 0; -+*/ -+ -+ return display; -+err3: -+ if (display->ctrl) -+ module_put(display->ctrl->owner); -+err2: -+ if (display->panel && display->panel->init) -+ display->panel->cleanup(display); -+err1: -+ if (display->panel) -+ module_put(display->panel->owner); -+err0: -+ return NULL; -+} -+EXPORT_SYMBOL(omap_dss_get_display); -+ -+void omap_dss_put_display(struct omap_display *display) -+{ -+ if (--display->ref_count > 0) -+ return; -+/* -+ if (atomic_cmpxchg(&display->ref_count, 1, 0) != 1) -+ return; -+*/ -+ if (display->ctrl) { -+ if (display->ctrl->cleanup) -+ display->ctrl->cleanup(display); -+ module_put(display->ctrl->owner); -+ } -+ -+ if (display->panel) { -+ if (display->panel->cleanup) -+ display->panel->cleanup(display); -+ module_put(display->panel->owner); -+ } -+} -+EXPORT_SYMBOL(omap_dss_put_display); -+ -+void omap_dss_register_ctrl(struct omap_ctrl *ctrl) -+{ -+ int i; -+ -+ for (i = 0; i < num_displays; i++) { -+ struct omap_display *display = &displays[i]; -+ if (display->hw_config.ctrl_name && -+ strcmp(display->hw_config.ctrl_name, ctrl->name) == 0) { -+ display->ctrl = ctrl; -+ DSSDBG("ctrl '%s' registered\n", ctrl->name); -+ } -+ } -+} -+EXPORT_SYMBOL(omap_dss_register_ctrl); -+ -+void omap_dss_register_panel(struct omap_panel *panel) -+{ -+ int i; -+ -+ for (i = 0; i < num_displays; i++) { -+ struct omap_display *display = &displays[i]; -+ if (display->hw_config.panel_name && -+ strcmp(display->hw_config.panel_name, panel->name) == 0) { -+ display->panel = panel; -+ DSSDBG("panel '%s' registered\n", panel->name); -+ } -+ } -+} -+EXPORT_SYMBOL(omap_dss_register_panel); -+ -+void omap_dss_unregister_ctrl(struct omap_ctrl *ctrl) -+{ -+ int i; -+ -+ for (i = 0; i < num_displays; i++) { -+ struct omap_display *display = &displays[i]; -+ if (display->hw_config.ctrl_name && -+ strcmp(display->hw_config.ctrl_name, ctrl->name) == 0) -+ display->ctrl = NULL; -+ } -+} -+EXPORT_SYMBOL(omap_dss_unregister_ctrl); -+ -+void omap_dss_unregister_panel(struct omap_panel *panel) -+{ -+ int i; -+ -+ for (i = 0; i < num_displays; i++) { -+ struct omap_display *display = &displays[i]; -+ if (display->hw_config.panel_name && -+ strcmp(display->hw_config.panel_name, panel->name) == 0) -+ display->panel = NULL; -+ } -+} -+EXPORT_SYMBOL(omap_dss_unregister_panel); -diff --git a/arch/arm/plat-omap/dss/dpi.c b/arch/arm/plat-omap/dss/dpi.c -new file mode 100644 -index 0000000..2dd8a3b ---- /dev/null -+++ b/arch/arm/plat-omap/dss/dpi.c -@@ -0,0 +1,344 @@ -+/* -+ * linux/arch/arm/plat-omap/dss/dpi.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/kernel.h> -+#include <linux/clk.h> -+#include <linux/delay.h> -+#include <linux/errno.h> -+ -+#include <mach/board.h> -+#include <mach/display.h> -+#include "dss.h" -+ -+ -+static struct { -+ int update_enabled; -+} dpi; -+ -+static void dpi_set_mode(struct omap_display *display) -+{ -+ struct omap_panel *panel = display->panel; -+ int lck_div, pck_div; -+ unsigned long fck; -+ unsigned long pck; -+ int is_tft; -+ -+ dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); -+ -+ dispc_set_pol_freq(panel); -+ -+ is_tft = (display->panel->config & OMAP_DSS_LCD_TFT) != 0; -+ -+#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL -+ { -+ struct dsi_clock_info cinfo; -+ dsi_pll_calc_pck(is_tft, -+ display->panel->timings.pixel_clock * 1000, -+ &cinfo); -+ -+ dsi_pll_program(&cinfo); -+ -+ dss_select_clk_source(0, 1); -+ -+ dispc_set_lcd_divisor(cinfo.lck_div, cinfo.pck_div); -+ -+ fck = cinfo.dispc_fck; -+ lck_div = cinfo.lck_div; -+ pck_div = cinfo.pck_div; -+ } -+#else -+ { -+ struct dispc_clock_info cinfo; -+ dispc_calc_clock_div(is_tft, panel->timings.pixel_clock * 1000, -+ &cinfo); -+ -+ if (dispc_set_clock_div(&cinfo)) { -+ DSSERR("Failed to set DSS clocks\n"); -+ dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); -+ return; -+ } -+ -+ fck = cinfo.fck; -+ lck_div = cinfo.lck_div; -+ pck_div = cinfo.pck_div; -+ } -+#endif -+ -+ pck = fck / lck_div / pck_div / 1000; -+ -+ if (pck != panel->timings.pixel_clock) { -+ DSSWARN("Could not find exact pixel clock. " -+ "Requested %d kHz, got %lu kHz\n", -+ panel->timings.pixel_clock, pck); -+ -+ panel->timings.pixel_clock = pck; -+ } -+ -+ dispc_set_lcd_timings(&panel->timings); -+ -+ dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); -+} -+ -+ -+static int dpi_display_enable(struct omap_display *display) -+{ -+ struct omap_panel *panel = display->panel; -+ int r; -+ int is_tft; -+ unsigned high, low, burst; -+ -+ if (display->state != OMAP_DSS_DISPLAY_DISABLED) { -+ DSSERR("display already enabled\n"); -+ return -EINVAL; -+ } -+ -+ r = panel->enable(display); -+ if (r) -+ return r; -+ -+ dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); -+ -+#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL -+ dss_clk_enable(DSS_CLK_FCK2); -+ r = dsi_pll_init(0, 1); -+ if (r) -+ return r; -+#endif -+ is_tft = (display->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(display->hw_config.u.dpi.data_lines); -+ -+ dispc_set_burst_size(OMAP_DSS_GFX, OMAP_DSS_BURST_16x32); -+ dispc_set_burst_size(OMAP_DSS_VIDEO1, OMAP_DSS_BURST_16x32); -+ dispc_set_burst_size(OMAP_DSS_VIDEO2, OMAP_DSS_BURST_16x32); -+ -+ burst = 16 * 32 / 8; -+ -+ high = dispc_get_plane_fifo_size(OMAP_DSS_GFX) - burst; -+ low = dispc_get_plane_fifo_size(OMAP_DSS_GFX) / 4; -+ dispc_setup_plane_fifo(OMAP_DSS_GFX, low, high); -+ -+ high = dispc_get_plane_fifo_size(OMAP_DSS_VIDEO1) - burst; -+ low = dispc_get_plane_fifo_size(OMAP_DSS_VIDEO1) / 4; -+ dispc_setup_plane_fifo(OMAP_DSS_VIDEO1, low, high); -+ -+ high = dispc_get_plane_fifo_size(OMAP_DSS_VIDEO2) - burst; -+ low = dispc_get_plane_fifo_size(OMAP_DSS_VIDEO2) / 4; -+ dispc_setup_plane_fifo(OMAP_DSS_VIDEO2, low, high); -+ -+ dpi_set_mode(display); -+ -+ mdelay(2); -+ -+ dispc_enable_lcd_out(1); -+ -+ display->state = OMAP_DSS_DISPLAY_ACTIVE; -+ -+ return 0; -+} -+ -+static int dpi_display_resume(struct omap_display *display); -+ -+static void dpi_display_disable(struct omap_display *display) -+{ -+ if (display->state == OMAP_DSS_DISPLAY_DISABLED) -+ return; -+ -+ if (display->state == OMAP_DSS_DISPLAY_SUSPENDED) -+ dpi_display_resume(display); -+ -+ display->panel->disable(display); -+ 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); -+ -+ display->state = OMAP_DSS_DISPLAY_DISABLED; -+} -+ -+static int dpi_display_suspend(struct omap_display *display) -+{ -+ if (display->state != OMAP_DSS_DISPLAY_ACTIVE) -+ return -EINVAL; -+ -+ if (display->panel->suspend) -+ display->panel->suspend(display); -+ -+ dispc_enable_lcd_out(0); -+ -+ dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); -+ -+ display->state = OMAP_DSS_DISPLAY_SUSPENDED; -+ -+ return 0; -+} -+ -+static int dpi_display_resume(struct omap_display *display) -+{ -+ if (display->state != OMAP_DSS_DISPLAY_SUSPENDED) -+ return -EINVAL; -+ -+ dispc_enable_lcd_out(1); -+ -+ dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); -+ -+ if (display->panel->resume) -+ display->panel->resume(display); -+ -+ display->state = OMAP_DSS_DISPLAY_ACTIVE; -+ -+ return 0; -+} -+ -+static void dpi_set_timings(struct omap_display *display, -+ struct omap_video_timings *timings) -+{ -+ DSSDBG("dpi_set_timings\n"); -+ display->panel->timings = *timings; -+ if (display->state == OMAP_DSS_DISPLAY_ACTIVE) { -+ dpi_set_mode(display); -+ dispc_go(OMAP_DSS_CHANNEL_LCD); -+ } -+} -+ -+static int dpi_check_timings(struct omap_display *display, -+ struct omap_video_timings *timings) -+{ -+ int is_tft; -+ int r; -+ int lck_div, pck_div; -+ unsigned long fck; -+ unsigned long pck; -+ -+ if (timings->hsw < 1 || timings->hsw > 64 || -+ timings->hfp < 1 || timings->hfp > 256 || -+ timings->hbp < 1 || timings->hbp > 256) { -+ return -EINVAL; -+ } -+ -+ if (timings->vsw < 1 || timings->vsw > 64 || -+ timings->vfp > 256 || timings->vbp > 256) { -+ return -EINVAL; -+ } -+ -+ if (timings->pixel_clock == 0) -+ return -EINVAL; -+ -+ is_tft = (display->panel->config & OMAP_DSS_LCD_TFT) != 0; -+ -+#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL -+ { -+ struct dsi_clock_info cinfo; -+ r = dsi_pll_calc_pck(is_tft, timings->pixel_clock * 1000, -+ &cinfo); -+ -+ if (r) -+ return r; -+ -+ fck = cinfo.dispc_fck; -+ lck_div = cinfo.lck_div; -+ pck_div = cinfo.pck_div; -+ } -+#else -+ { -+ struct dispc_clock_info cinfo; -+ r = dispc_calc_clock_div(is_tft, timings->pixel_clock * 1000, -+ &cinfo); -+ -+ if (r) -+ return r; -+ -+ fck = cinfo.fck; -+ lck_div = cinfo.lck_div; -+ pck_div = cinfo.pck_div; -+ } -+#endif -+ -+ pck = fck / lck_div / pck_div / 1000; -+ -+ timings->pixel_clock = pck; -+ -+ return 0; -+} -+ -+static void dpi_get_timings(struct omap_display *display, -+ struct omap_video_timings *timings) -+{ -+ *timings = display->panel->timings; -+} -+ -+static int dpi_display_set_update_mode(struct omap_display *display, -+ 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_display *display) -+{ -+ return dpi.update_enabled ? OMAP_DSS_UPDATE_AUTO : -+ OMAP_DSS_UPDATE_DISABLED; -+} -+ -+void dpi_init_display(struct omap_display *display) -+{ -+ DSSDBG("DPI init_display\n"); -+ -+ display->enable = dpi_display_enable; -+ display->disable = dpi_display_disable; -+ display->suspend = dpi_display_suspend; -+ display->resume = dpi_display_resume; -+ display->set_timings = dpi_set_timings; -+ display->check_timings = dpi_check_timings; -+ display->get_timings = dpi_get_timings; -+ display->set_update_mode = dpi_display_set_update_mode; -+ display->get_update_mode = dpi_display_get_update_mode; -+} -+ -+int dpi_init(void) -+{ -+ return 0; -+} -+ -+void dpi_exit(void) -+{ -+} -+ -diff --git a/arch/arm/plat-omap/dss/dsi.c b/arch/arm/plat-omap/dss/dsi.c -new file mode 100644 -index 0000000..e279571 ---- /dev/null -+++ b/arch/arm/plat-omap/dss/dsi.c -@@ -0,0 +1,3187 @@ -+/* -+ * linux/arch/arm/plat-omap/dss/dsi.c -+ * -+ * 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/>. -+ */ -+ -+#define DSS_SUBSYS_NAME "DSI" -+ -+#include <linux/kernel.h> -+#include <linux/io.h> -+#include <linux/clk.h> -+#include <linux/device.h> -+#include <linux/err.h> -+#include <linux/interrupt.h> -+#include <linux/delay.h> -+#include <linux/workqueue.h> -+#include <linux/mutex.h> -+ -+#include <mach/board.h> -+#include <mach/display.h> -+#include <mach/clock.h> -+ -+#include "dss.h" -+ -+/*#define VERBOSE*/ -+/*#define VERBOSE_IRQ*/ -+/*#define MEASURE_PERF*/ -+ -+#define DSI_BASE 0x4804FC00 -+ -+struct dsi_reg { u16 idx; }; -+ -+#define DSI_REG(idx) ((const struct dsi_reg) { idx }) -+ -+#define DSI_SZ_REGS SZ_1K -+/* DSI Protocol Engine */ -+ -+#define DSI_REVISION DSI_REG(0x0000) -+#define DSI_SYSCONFIG DSI_REG(0x0010) -+#define DSI_SYSSTATUS DSI_REG(0x0014) -+#define DSI_IRQSTATUS DSI_REG(0x0018) -+#define DSI_IRQENABLE DSI_REG(0x001C) -+#define DSI_CTRL DSI_REG(0x0040) -+#define DSI_COMPLEXIO_CFG1 DSI_REG(0x0048) -+#define DSI_COMPLEXIO_IRQ_STATUS DSI_REG(0x004C) -+#define DSI_COMPLEXIO_IRQ_ENABLE DSI_REG(0x0050) -+#define DSI_CLK_CTRL DSI_REG(0x0054) -+#define DSI_TIMING1 DSI_REG(0x0058) -+#define DSI_TIMING2 DSI_REG(0x005C) -+#define DSI_VM_TIMING1 DSI_REG(0x0060) -+#define DSI_VM_TIMING2 DSI_REG(0x0064) -+#define DSI_VM_TIMING3 DSI_REG(0x0068) -+#define DSI_CLK_TIMING DSI_REG(0x006C) -+#define DSI_TX_FIFO_VC_SIZE DSI_REG(0x0070) -+#define DSI_RX_FIFO_VC_SIZE DSI_REG(0x0074) -+#define DSI_COMPLEXIO_CFG2 DSI_REG(0x0078) -+#define DSI_RX_FIFO_VC_FULLNESS DSI_REG(0x007C) -+#define DSI_VM_TIMING4 DSI_REG(0x0080) -+#define DSI_TX_FIFO_VC_EMPTINESS DSI_REG(0x0084) -+#define DSI_VM_TIMING5 DSI_REG(0x0088) -+#define DSI_VM_TIMING6 DSI_REG(0x008C) -+#define DSI_VM_TIMING7 DSI_REG(0x0090) -+#define DSI_STOPCLK_TIMING DSI_REG(0x0094) -+#define DSI_VC_CTRL(n) DSI_REG(0x0100 + (n * 0x20)) -+#define DSI_VC_TE(n) DSI_REG(0x0104 + (n * 0x20)) -+#define DSI_VC_LONG_PACKET_HEADER(n) DSI_REG(0x0108 + (n * 0x20)) -+#define DSI_VC_LONG_PACKET_PAYLOAD(n) DSI_REG(0x010C + (n * 0x20)) -+#define DSI_VC_SHORT_PACKET_HEADER(n) DSI_REG(0x0110 + (n * 0x20)) -+#define DSI_VC_IRQSTATUS(n) DSI_REG(0x0118 + (n * 0x20)) -+#define DSI_VC_IRQENABLE(n) DSI_REG(0x011C + (n * 0x20)) -+ -+/* DSIPHY_SCP */ -+ -+#define DSI_DSIPHY_CFG0 DSI_REG(0x200 + 0x0000) -+#define DSI_DSIPHY_CFG1 DSI_REG(0x200 + 0x0004) -+#define DSI_DSIPHY_CFG2 DSI_REG(0x200 + 0x0008) -+#define DSI_DSIPHY_CFG5 DSI_REG(0x200 + 0x0014) -+ -+/* DSI_PLL_CTRL_SCP */ -+ -+#define DSI_PLL_CONTROL DSI_REG(0x300 + 0x0000) -+#define DSI_PLL_STATUS DSI_REG(0x300 + 0x0004) -+#define DSI_PLL_GO DSI_REG(0x300 + 0x0008) -+#define DSI_PLL_CONFIGURATION1 DSI_REG(0x300 + 0x000C) -+#define DSI_PLL_CONFIGURATION2 DSI_REG(0x300 + 0x0010) -+ -+#define REG_GET(idx, start, end) \ -+ FLD_GET(dsi_read_reg(idx), start, end) -+ -+#define REG_FLD_MOD(idx, val, start, end) \ -+ dsi_write_reg(idx, FLD_MOD(dsi_read_reg(idx), val, start, end)) -+ -+/* Global interrupts */ -+#define DSI_IRQ_VC0 (1 << 0) -+#define DSI_IRQ_VC1 (1 << 1) -+#define DSI_IRQ_VC2 (1 << 2) -+#define DSI_IRQ_VC3 (1 << 3) -+#define DSI_IRQ_WAKEUP (1 << 4) -+#define DSI_IRQ_RESYNC (1 << 5) -+#define DSI_IRQ_PLL_LOCK (1 << 7) -+#define DSI_IRQ_PLL_UNLOCK (1 << 8) -+#define DSI_IRQ_PLL_RECALL (1 << 9) -+#define DSI_IRQ_COMPLEXIO_ERR (1 << 10) -+#define DSI_IRQ_HS_TX_TIMEOUT (1 << 14) -+#define DSI_IRQ_LP_RX_TIMEOUT (1 << 15) -+#define DSI_IRQ_TE_TRIGGER (1 << 16) -+#define DSI_IRQ_ACK_TRIGGER (1 << 17) -+#define DSI_IRQ_SYNC_LOST (1 << 18) -+#define DSI_IRQ_LDO_POWER_GOOD (1 << 19) -+#define DSI_IRQ_TA_TIMEOUT (1 << 20) -+#define DSI_IRQ_ERROR_MASK \ -+ (DSI_IRQ_HS_TX_TIMEOUT | DSI_IRQ_LP_RX_TIMEOUT | DSI_IRQ_SYNC_LOST | \ -+ DSI_IRQ_TA_TIMEOUT) -+#define DSI_IRQ_CHANNEL_MASK 0xf -+ -+/* Virtual channel interrupts */ -+#define DSI_VC_IRQ_CS (1 << 0) -+#define DSI_VC_IRQ_ECC_CORR (1 << 1) -+#define DSI_VC_IRQ_PACKET_SENT (1 << 2) -+#define DSI_VC_IRQ_FIFO_TX_OVF (1 << 3) -+#define DSI_VC_IRQ_FIFO_RX_OVF (1 << 4) -+#define DSI_VC_IRQ_BTA (1 << 5) -+#define DSI_VC_IRQ_ECC_NO_CORR (1 << 6) -+#define DSI_VC_IRQ_FIFO_TX_UDF (1 << 7) -+#define DSI_VC_IRQ_PP_BUSY_CHANGE (1 << 8) -+#define DSI_VC_IRQ_ERROR_MASK \ -+ (DSI_VC_IRQ_CS | DSI_VC_IRQ_ECC_CORR | DSI_VC_IRQ_FIFO_TX_OVF | \ -+ DSI_VC_IRQ_FIFO_RX_OVF | DSI_VC_IRQ_ECC_NO_CORR | \ -+ DSI_VC_IRQ_FIFO_TX_UDF) -+ -+/* ComplexIO interrupts */ -+#define DSI_CIO_IRQ_ERRSYNCESC1 (1 << 0) -+#define DSI_CIO_IRQ_ERRSYNCESC2 (1 << 1) -+#define DSI_CIO_IRQ_ERRSYNCESC3 (1 << 2) -+#define DSI_CIO_IRQ_ERRESC1 (1 << 5) -+#define DSI_CIO_IRQ_ERRESC2 (1 << 6) -+#define DSI_CIO_IRQ_ERRESC3 (1 << 7) -+#define DSI_CIO_IRQ_ERRCONTROL1 (1 << 10) -+#define DSI_CIO_IRQ_ERRCONTROL2 (1 << 11) -+#define DSI_CIO_IRQ_ERRCONTROL3 (1 << 12) -+#define DSI_CIO_IRQ_STATEULPS1 (1 << 15) -+#define DSI_CIO_IRQ_STATEULPS2 (1 << 16) -+#define DSI_CIO_IRQ_STATEULPS3 (1 << 17) -+#define DSI_CIO_IRQ_ERRCONTENTIONLP0_1 (1 << 20) -+#define DSI_CIO_IRQ_ERRCONTENTIONLP1_1 (1 << 21) -+#define DSI_CIO_IRQ_ERRCONTENTIONLP0_2 (1 << 22) -+#define DSI_CIO_IRQ_ERRCONTENTIONLP1_2 (1 << 23) -+#define DSI_CIO_IRQ_ERRCONTENTIONLP0_3 (1 << 24) -+#define DSI_CIO_IRQ_ERRCONTENTIONLP1_3 (1 << 25) -+#define DSI_CIO_IRQ_ULPSACTIVENOT_ALL0 (1 << 30) -+#define DSI_CIO_IRQ_ULPSACTIVENOT_ALL1 (1 << 31) -+ -+#define DSI_DT_DCS_SHORT_WRITE_0 0x05 -+#define DSI_DT_DCS_SHORT_WRITE_1 0x15 -+#define DSI_DT_DCS_READ 0x06 -+#define DSI_DT_SET_MAX_RET_PKG_SIZE 0x37 -+#define DSI_DT_NULL_PACKET 0x09 -+#define DSI_DT_DCS_LONG_WRITE 0x39 -+ -+#define DSI_DT_RX_ACK_WITH_ERR 0x02 -+#define DSI_DT_RX_DCS_LONG_READ 0x1c -+#define DSI_DT_RX_SHORT_READ_1 0x21 -+#define DSI_DT_RX_SHORT_READ_2 0x22 -+ -+#define FINT_MAX 2100000 -+#define FINT_MIN 750000 -+#define REGN_MAX (1 << 7) -+#define REGM_MAX ((1 << 11) - 1) -+#define REGM3_MAX (1 << 4) -+#define REGM4_MAX (1 << 4) -+ -+enum fifo_size { -+ DSI_FIFO_SIZE_0 = 0, -+ DSI_FIFO_SIZE_32 = 1, -+ DSI_FIFO_SIZE_64 = 2, -+ DSI_FIFO_SIZE_96 = 3, -+ DSI_FIFO_SIZE_128 = 4, -+}; -+ -+static struct -+{ -+ void __iomem *base; -+ -+ unsigned long dsi1_pll_fclk; /* Hz */ -+ unsigned long dsi2_pll_fclk; /* Hz */ -+ unsigned long dsiphy; /* Hz */ -+ unsigned long ddr_clk; /* Hz */ -+ -+ u32 ctx[DSI_SZ_REGS / sizeof(u32)]; -+ -+ struct { -+ enum fifo_size fifo_size; -+ int dest_per; /* destination peripheral 0-3 */ -+ } vc[4]; -+ -+ struct mutex lock; -+ -+ unsigned pll_locked; -+ -+ struct completion bta_completion; -+ -+ spinlock_t update_lock; -+ int update_ongoing; -+ int update_syncers; -+ struct completion update_completion; -+ struct delayed_work framedone_work; -+ -+ enum omap_dss_update_mode user_update_mode; /* what the user wants */ -+ enum omap_dss_update_mode update_mode; /* current mode */ -+ int use_te; -+ int framedone_scheduled; /* helps to catch strange framedone bugs */ -+ -+ struct { -+ struct omap_display *display; -+ int x, y, w, h; -+ int bytespp; -+ } update_region; -+ -+ unsigned long cache_req_pck; -+ unsigned long cache_clk_freq; -+ struct dsi_clock_info cache_cinfo; -+ -+#ifdef MEASURE_PERF -+ ktime_t perf_setup_time; -+ ktime_t perf_start_time; -+ int perf_measure_frames; -+#endif -+} dsi; -+ -+static inline void dsi_write_reg(const struct dsi_reg idx, u32 val) -+{ -+ __raw_writel(val, dsi.base + idx.idx); -+} -+ -+static inline u32 dsi_read_reg(const struct dsi_reg idx) -+{ -+ return __raw_readl(dsi.base + idx.idx); -+} -+ -+ -+#define SR(reg) \ -+ dsi.ctx[(DSI_##reg).idx / sizeof(u32)] = dsi_read_reg(DSI_##reg) -+#define RR(reg) \ -+ dsi_write_reg(DSI_##reg, dsi.ctx[(DSI_##reg).idx / sizeof(u32)]) -+ -+void dsi_save_context(void) -+{ -+ SR(SYSCONFIG); -+ SR(IRQENABLE); -+ SR(CTRL); -+ SR(COMPLEXIO_CFG1); -+ SR(COMPLEXIO_IRQ_ENABLE); -+ SR(CLK_CTRL); -+ SR(TIMING1); -+ SR(TIMING2); -+ SR(VM_TIMING1); -+ SR(VM_TIMING2); -+ SR(VM_TIMING3); -+ SR(CLK_TIMING); -+ SR(TX_FIFO_VC_SIZE); -+ SR(RX_FIFO_VC_SIZE); -+ SR(COMPLEXIO_CFG2); -+ SR(VM_TIMING4); -+ SR(VM_TIMING5); -+ SR(VM_TIMING6); -+ SR(VM_TIMING7); -+ SR(STOPCLK_TIMING); -+ -+ SR(VC_CTRL(0)); -+ SR(VC_TE(0)); -+ SR(VC_IRQENABLE(0)); -+ -+ SR(VC_CTRL(1)); -+ SR(VC_TE(1)); -+ SR(VC_IRQENABLE(1)); -+ -+ SR(VC_CTRL(2)); -+ SR(VC_TE(2)); -+ SR(VC_IRQENABLE(2)); -+ -+ SR(VC_CTRL(3)); -+ SR(VC_TE(3)); -+ SR(VC_IRQENABLE(3)); -+ -+ SR(DSIPHY_CFG0); -+ SR(DSIPHY_CFG1); -+ SR(DSIPHY_CFG2); -+ SR(DSIPHY_CFG5); -+ -+ SR(PLL_CONTROL); -+ SR(PLL_CONFIGURATION1); -+ SR(PLL_CONFIGURATION2); -+} -+ -+void dsi_restore_context(void) -+{ -+ RR(SYSCONFIG); -+ RR(IRQENABLE); -+ RR(CTRL); -+ RR(COMPLEXIO_CFG1); -+ RR(COMPLEXIO_IRQ_ENABLE); -+ RR(CLK_CTRL); -+ RR(TIMING1); -+ RR(TIMING2); -+ RR(VM_TIMING1); -+ RR(VM_TIMING2); -+ RR(VM_TIMING3); -+ RR(CLK_TIMING); -+ RR(TX_FIFO_VC_SIZE); -+ RR(RX_FIFO_VC_SIZE); -+ RR(COMPLEXIO_CFG2); -+ RR(VM_TIMING4); -+ RR(VM_TIMING5); -+ RR(VM_TIMING6); -+ RR(VM_TIMING7); -+ RR(STOPCLK_TIMING); -+ -+ RR(VC_CTRL(0)); -+ RR(VC_IRQENABLE(0)); -+ -+ RR(VC_CTRL(1)); -+ RR(VC_IRQENABLE(1)); -+ -+ RR(VC_CTRL(2)); -+ RR(VC_IRQENABLE(2)); -+ -+ RR(VC_CTRL(3)); -+ RR(VC_IRQENABLE(3)); -+ -+ RR(DSIPHY_CFG0); -+ RR(DSIPHY_CFG1); -+ RR(DSIPHY_CFG2); -+ RR(DSIPHY_CFG5); -+ -+ RR(PLL_CONTROL); -+ RR(PLL_CONFIGURATION1); -+ RR(PLL_CONFIGURATION2); -+} -+ -+#undef SR -+#undef RR -+ -+static inline int wait_for_bit_change(const struct dsi_reg idx, int bitnum, -+ int value) -+{ -+ int t = 100000; -+ -+ while (REG_GET(idx, bitnum, bitnum) != value) { -+ if (--t == 0) -+ return !value; -+ } -+ -+ return value; -+} -+ -+ -+#ifdef MEASURE_PERF -+static void perf_mark_setup(void) -+{ -+ dsi.perf_setup_time = ktime_get(); -+} -+ -+static void perf_mark_start(void) -+{ -+ dsi.perf_start_time = ktime_get(); -+} -+ -+static void perf_show(const char *name) -+{ -+ ktime_t t, setup_time, trans_time; -+ u32 total_bytes; -+ u32 setup_us, trans_us, total_us; -+ const int numframes = 100; -+ static u32 s_trans_us, s_min_us = 0xffffffff, s_max_us; -+ -+ if (dsi.update_mode == OMAP_DSS_UPDATE_DISABLED) -+ return; -+ -+ t = ktime_get(); -+ -+ setup_time = ktime_sub(dsi.perf_start_time, dsi.perf_setup_time); -+ setup_us = (u32)ktime_to_us(setup_time); -+ if (setup_us == 0) -+ setup_us = 1; -+ -+ trans_time = ktime_sub(t, dsi.perf_start_time); -+ trans_us = (u32)ktime_to_us(trans_time); -+ if (trans_us == 0) -+ trans_us = 1; -+ -+ total_us = setup_us + trans_us; -+ -+ total_bytes = dsi.update_region.w * -+ dsi.update_region.h * -+ dsi.update_region.bytespp; -+ -+ if (dsi.update_mode == OMAP_DSS_UPDATE_AUTO) { -+ dsi.perf_measure_frames++; -+ -+ if (trans_us < s_min_us) -+ s_min_us = trans_us; -+ -+ if (trans_us > s_max_us) -+ s_max_us = trans_us; -+ -+ s_trans_us += trans_us; -+ -+ if (dsi.perf_measure_frames < numframes) -+ return; -+ -+ DSSINFO("%s update: %d frames in %u us (min/max %u/%u), " -+ "%u fps\n", -+ name, numframes, -+ s_trans_us, -+ s_min_us, -+ s_max_us, -+ 1000*1000 / (s_trans_us / numframes)); -+ -+ dsi.perf_measure_frames = 0; -+ s_trans_us = 0; -+ s_min_us = 0xffffffff; -+ s_max_us = 0; -+ } else { -+ DSSINFO("%s update %u us + %u us = %u us (%uHz), %u bytes, " -+ "%u kbytes/sec\n", -+ name, -+ setup_us, -+ trans_us, -+ total_us, -+ 1000*1000 / total_us, -+ total_bytes, -+ total_bytes * 1000 / total_us); -+ } -+} -+#else -+#define perf_mark_setup() -+#define perf_mark_start() -+#define perf_show(x) -+#endif -+ -+ -+ -+ -+static void print_irq_status(u32 status) -+{ -+#ifndef VERBOSE_IRQ -+ if ((status & ~DSI_IRQ_CHANNEL_MASK) == 0) -+ return; -+#endif -+ printk(KERN_DEBUG "DSI IRQ: 0x%x: ", status); -+ -+#define PIS(x) \ -+ if (status & DSI_IRQ_##x) \ -+ printk(#x " "); -+#ifdef VERBOSE_IRQ -+ PIS(VC0); -+ PIS(VC1); -+ PIS(VC2); -+ PIS(VC3); -+#endif -+ PIS(WAKEUP); -+ PIS(RESYNC); -+ PIS(PLL_LOCK); -+ PIS(PLL_UNLOCK); -+ PIS(PLL_RECALL); -+ PIS(COMPLEXIO_ERR); -+ PIS(HS_TX_TIMEOUT); -+ PIS(LP_RX_TIMEOUT); -+ PIS(TE_TRIGGER); -+ PIS(ACK_TRIGGER); -+ PIS(SYNC_LOST); -+ PIS(LDO_POWER_GOOD); -+ PIS(TA_TIMEOUT); -+#undef PIS -+ -+ printk("\n"); -+} -+ -+static void print_irq_status_vc(int channel, u32 status) -+{ -+#ifndef VERBOSE_IRQ -+ if ((status & ~DSI_VC_IRQ_PACKET_SENT) == 0) -+ return; -+#endif -+ printk(KERN_DEBUG "DSI VC(%d) IRQ 0x%x: ", channel, status); -+ -+#define PIS(x) \ -+ if (status & DSI_VC_IRQ_##x) \ -+ printk(#x " "); -+ PIS(CS); -+ PIS(ECC_CORR); -+#ifdef VERBOSE_IRQ -+ PIS(PACKET_SENT); -+#endif -+ PIS(FIFO_TX_OVF); -+ PIS(FIFO_RX_OVF); -+ PIS(BTA); -+ PIS(ECC_NO_CORR); -+ PIS(FIFO_TX_UDF); -+ PIS(PP_BUSY_CHANGE); -+#undef PIS -+ printk("\n"); -+} -+ -+static void print_irq_status_cio(u32 status) -+{ -+ printk(KERN_DEBUG "DSI CIO IRQ 0x%x: ", status); -+ -+#define PIS(x) \ -+ if (status & DSI_CIO_IRQ_##x) \ -+ printk(#x " "); -+ PIS(ERRSYNCESC1); -+ PIS(ERRSYNCESC2); -+ PIS(ERRSYNCESC3); -+ PIS(ERRESC1); -+ PIS(ERRESC2); -+ PIS(ERRESC3); -+ PIS(ERRCONTROL1); -+ PIS(ERRCONTROL2); -+ PIS(ERRCONTROL3); -+ PIS(STATEULPS1); -+ PIS(STATEULPS2); -+ PIS(STATEULPS3); -+ PIS(ERRCONTENTIONLP0_1); -+ PIS(ERRCONTENTIONLP1_1); -+ PIS(ERRCONTENTIONLP0_2); -+ PIS(ERRCONTENTIONLP1_2); -+ PIS(ERRCONTENTIONLP0_3); -+ PIS(ERRCONTENTIONLP1_3); -+ PIS(ULPSACTIVENOT_ALL0); -+ PIS(ULPSACTIVENOT_ALL1); -+#undef PIS -+ -+ printk("\n"); -+} -+ -+static int debug_irq; -+ -+/* called from dss */ -+void dsi_irq_handler(void) -+{ -+ u32 irqstatus, vcstatus, ciostatus; -+ int i; -+ -+ irqstatus = dsi_read_reg(DSI_IRQSTATUS); -+ -+ if (irqstatus & DSI_IRQ_ERROR_MASK) { -+ DSSERR("DSI error, irqstatus %x\n", irqstatus); -+ print_irq_status(irqstatus); -+ } else if (debug_irq) { -+ print_irq_status(irqstatus); -+ } -+ -+ for (i = 0; i < 4; ++i) { -+ if ((irqstatus & (1<<i)) == 0) -+ continue; -+ -+ vcstatus = dsi_read_reg(DSI_VC_IRQSTATUS(i)); -+ -+ if (vcstatus & DSI_VC_IRQ_BTA) -+ complete(&dsi.bta_completion); -+ -+ if (vcstatus & DSI_VC_IRQ_ERROR_MASK) { -+ DSSERR("DSI VC(%d) error, vc irqstatus %x\n", -+ i, vcstatus); -+ print_irq_status_vc(i, vcstatus); -+ } else if (debug_irq) { -+ print_irq_status_vc(i, vcstatus); -+ } -+ -+ dsi_write_reg(DSI_VC_IRQSTATUS(i), vcstatus); -+ } -+ -+ if (irqstatus & DSI_IRQ_COMPLEXIO_ERR) { -+ ciostatus = dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS); -+ -+ dsi_write_reg(DSI_COMPLEXIO_IRQ_STATUS, ciostatus); -+ -+ DSSERR("DSI CIO error, cio irqstatus %x\n", ciostatus); -+ print_irq_status_cio(ciostatus); -+ } -+ -+ dsi_write_reg(DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK); -+} -+ -+ -+static void _dsi_initialize_irq(void) -+{ -+ u32 l; -+ int i; -+ -+ /* disable all interrupts */ -+ dsi_write_reg(DSI_IRQENABLE, 0); -+ for (i = 0; i < 4; ++i) -+ dsi_write_reg(DSI_VC_IRQENABLE(i), 0); -+ dsi_write_reg(DSI_COMPLEXIO_IRQ_ENABLE, 0); -+ -+ /* clear interrupt status */ -+ l = dsi_read_reg(DSI_IRQSTATUS); -+ dsi_write_reg(DSI_IRQSTATUS, l & ~DSI_IRQ_CHANNEL_MASK); -+ -+ for (i = 0; i < 4; ++i) { -+ l = dsi_read_reg(DSI_VC_IRQSTATUS(i)); -+ dsi_write_reg(DSI_VC_IRQSTATUS(i), l); -+ } -+ -+ l = dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS); -+ dsi_write_reg(DSI_COMPLEXIO_IRQ_STATUS, l); -+ -+ /* enable error irqs */ -+ l = DSI_IRQ_ERROR_MASK; -+ dsi_write_reg(DSI_IRQENABLE, l); -+ -+ l = DSI_VC_IRQ_ERROR_MASK; -+ for (i = 0; i < 4; ++i) -+ dsi_write_reg(DSI_VC_IRQENABLE(i), l); -+ -+ /* XXX zonda responds incorrectly, causing control error: -+ Exit from LP-ESC mode to LP11 uses wrong transition states on the -+ data lines LP0 and LN0. */ -+ dsi_write_reg(DSI_COMPLEXIO_IRQ_ENABLE, -+ -1 & (~DSI_CIO_IRQ_ERRCONTROL2)); -+} -+ -+static void dsi_vc_enable_bta_irq(int channel) -+{ -+ u32 l; -+ -+ l = dsi_read_reg(DSI_VC_IRQENABLE(channel)); -+ l |= DSI_VC_IRQ_BTA; -+ dsi_write_reg(DSI_VC_IRQENABLE(channel), l); -+} -+ -+static void dsi_vc_disable_bta_irq(int channel) -+{ -+ u32 l; -+ -+ l = dsi_read_reg(DSI_VC_IRQENABLE(channel)); -+ l &= ~DSI_VC_IRQ_BTA; -+ dsi_write_reg(DSI_VC_IRQENABLE(channel), l); -+} -+ -+/* DSI func clock. this could also be DSI2_PLL_FCLK */ -+static inline void enable_clocks(int enable) -+{ -+ if (enable) -+ dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); -+ else -+ dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); -+} -+ -+/* source clock for DSI PLL. this could also be PCLKFREE */ -+static inline void dsi_enable_pll_clock(int enable) -+{ -+ if (enable) -+ dss_clk_enable(DSS_CLK_FCK2); -+ else -+ dss_clk_disable(DSS_CLK_FCK2); -+ -+ if (enable && dsi.pll_locked) { -+ if (wait_for_bit_change(DSI_PLL_STATUS, 1, 1) != 1) -+ DSSERR("cannot lock PLL when enabling clocks\n"); -+ } -+} -+ -+#ifdef DEBUG -+static void _dsi_print_reset_status(void) -+{ -+ u32 l; -+ -+ if (!dss_debug) -+ return; -+ -+ /* A dummy read using the SCP interface to any DSIPHY register is -+ * required after DSIPHY reset to complete the reset of the DSI complex -+ * I/O. */ -+ l = dsi_read_reg(DSI_DSIPHY_CFG5); -+ -+ printk(KERN_DEBUG "DSI resets: "); -+ -+ l = dsi_read_reg(DSI_PLL_STATUS); -+ printk("PLL (%d) ", FLD_GET(l, 0, 0)); -+ -+ l = dsi_read_reg(DSI_COMPLEXIO_CFG1); -+ printk("CIO (%d) ", FLD_GET(l, 29, 29)); -+ -+ l = dsi_read_reg(DSI_DSIPHY_CFG5); -+ printk("PHY (%x, %d, %d, %d)\n", -+ FLD_GET(l, 28, 26), -+ FLD_GET(l, 29, 29), -+ FLD_GET(l, 30, 30), -+ FLD_GET(l, 31, 31)); -+} -+#else -+#define _dsi_print_reset_status() -+#endif -+ -+static inline int dsi_if_enable(int enable) -+{ -+ DSSDBG("dsi_if_enable(%d)\n", enable); -+ -+ enable = enable ? 1 : 0; -+ REG_FLD_MOD(DSI_CTRL, enable, 0, 0); /* IF_EN */ -+ -+ if (wait_for_bit_change(DSI_CTRL, 0, enable) != enable) { -+ DSSERR("Failed to set dsi_if_enable to %d\n", enable); -+ return -EIO; -+ } -+ -+ return 0; -+} -+ -+static unsigned long dsi_fclk_rate(void) -+{ -+ unsigned long r; -+ -+ if (dss_get_dsi_clk_source() == 0) { -+ /* DSI FCLK source is DSS1_ALWON_FCK, which is dss1_fck */ -+ r = dss_clk_get_rate(DSS_CLK_FCK1); -+ } else { -+ /* DSI FCLK source is DSI2_PLL_FCLK */ -+ r = dsi.dsi2_pll_fclk; -+ } -+ -+ return r; -+} -+ -+static int dsi_set_lp_clk_divisor(void) -+{ -+ int n; -+ unsigned long dsi_fclk; -+ unsigned long mhz; -+ -+ /* LP_CLK_DIVISOR, DSI fclk/n, should be 20MHz - 32kHz */ -+ -+ dsi_fclk = dsi_fclk_rate(); -+ -+ for (n = 1; n < (1 << 13) - 1; ++n) { -+ mhz = dsi_fclk / n; -+ if (mhz <= 20*1000*1000) -+ break; -+ } -+ -+ if (n == (1 << 13) - 1) { -+ DSSERR("Failed to find LP_CLK_DIVISOR\n"); -+ return -EINVAL; -+ } -+ -+ DSSDBG("LP_CLK_DIV %d, LP_CLK %ld\n", n, mhz); -+ -+ REG_FLD_MOD(DSI_CLK_CTRL, n, 12, 0); /* LP_CLK_DIVISOR */ -+ if (dsi_fclk > 30*1000*1000) -+ REG_FLD_MOD(DSI_CLK_CTRL, 1, 21, 21); /* LP_RX_SYNCHRO_ENABLE */ -+ -+ return 0; -+} -+ -+ -+enum dsi_pll_power_state { -+ DSI_PLL_POWER_OFF = 0x0, -+ DSI_PLL_POWER_ON_HSCLK = 0x1, -+ DSI_PLL_POWER_ON_ALL = 0x2, -+ DSI_PLL_POWER_ON_DIV = 0x3, -+}; -+ -+static int dsi_pll_power(enum dsi_pll_power_state state) -+{ -+ int t = 0; -+ -+ REG_FLD_MOD(DSI_CLK_CTRL, state, 31, 30); /* PLL_PWR_CMD */ -+ -+ /* PLL_PWR_STATUS */ -+ while (FLD_GET(dsi_read_reg(DSI_CLK_CTRL), 29, 28) != state) { -+ udelay(1); -+ if (t++ > 1000) { -+ DSSERR("Failed to set DSI PLL power mode to %d\n", -+ state); -+ return -ENODEV; -+ } -+ } -+ -+ return 0; -+} -+ -+int dsi_pll_calc_pck(int is_tft, unsigned long req_pck, -+ struct dsi_clock_info *cinfo) -+{ -+ struct dsi_clock_info cur, best; -+ int min_fck_per_pck; -+ int match = 0; -+ -+ if (req_pck == dsi.cache_req_pck && -+ dsi.cache_cinfo.clkin == dss_clk_get_rate(DSS_CLK_FCK2)) { -+ DSSDBG("DSI clock info found from cache\n"); -+ *cinfo = dsi.cache_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; -+ } -+ -+ DSSDBG("dsi_pll_calc\n"); -+ -+retry: -+ memset(&best, 0, sizeof(best)); -+ -+ memset(&cur, 0, sizeof(cur)); -+ cur.clkin = dss_clk_get_rate(DSS_CLK_FCK2); -+ cur.use_dss2_fck = 1; -+ cur.highfreq = 0; -+ -+ /* no highfreq: 0.75MHz < Fint = clkin / regn < 2.1MHz */ -+ /* highfreq: 0.75MHz < Fint = clkin / (2*regn) < 2.1MHz */ -+ /* To reduce PLL lock time, keep Fint high (around 2 MHz) */ -+ for (cur.regn = 1; cur.regn < REGN_MAX; ++cur.regn) { -+ if (cur.highfreq == 0) -+ cur.fint = cur.clkin / cur.regn; -+ else -+ cur.fint = cur.clkin / (2 * cur.regn); -+ -+ if (cur.fint > FINT_MAX || cur.fint < FINT_MIN) -+ continue; -+ -+ /* DSIPHY(MHz) = (2 * regm / regn) * (clkin / (highfreq + 1)) */ -+ for (cur.regm = 1; cur.regm < REGM_MAX; ++cur.regm) { -+ unsigned long a, b; -+ -+ a = 2 * cur.regm * (cur.clkin/1000); -+ b = cur.regn * (cur.highfreq + 1); -+ cur.dsiphy = a / b * 1000; -+ -+ if (cur.dsiphy > 1800 * 1000 * 1000) -+ break; -+ -+ /* DSI1_PLL_FCLK(MHz) = DSIPHY(MHz) / regm3 < 173MHz */ -+ for (cur.regm3 = 1; cur.regm3 < REGM3_MAX; -+ ++cur.regm3) { -+ cur.dispc_fck = cur.dsiphy / cur.regm3; -+ -+ /* this will narrow down the search a bit, -+ * but still give pixclocks below what was -+ * requested */ -+ if (cur.dispc_fck < req_pck) -+ break; -+ -+ if (cur.dispc_fck > DISPC_MAX_FCK) -+ continue; -+ -+ if (min_fck_per_pck && -+ cur.dispc_fck < -+ req_pck * min_fck_per_pck) -+ continue; -+ -+ match = 1; -+ -+ find_lck_pck_divs(is_tft, req_pck, -+ cur.dispc_fck, -+ &cur.lck_div, -+ &cur.pck_div); -+ -+ cur.lck = cur.dispc_fck / cur.lck_div; -+ cur.pck = cur.lck / cur.pck_div; -+ -+ if (abs(cur.pck - req_pck) < -+ abs(best.pck - req_pck)) { -+ best = cur; -+ -+ if (cur.pck == req_pck) -+ goto found; -+ } -+ } -+ } -+ } -+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; -+ } -+ -+ /* DSI2_PLL_FCLK(MHz) = DSIPHY(MHz) / regm4 < 173MHz */ -+ /* hardcoded 48MHz for now. what should it be? */ -+ best.regm4 = best.dsiphy / 48000000; -+ if (best.regm4 > REGM4_MAX) -+ best.regm4 = REGM4_MAX; -+ best.dsi_fck = best.dsiphy / best.regm4; -+ -+ if (cinfo) -+ *cinfo = best; -+ -+ dsi.cache_req_pck = req_pck; -+ dsi.cache_clk_freq = 0; -+ dsi.cache_cinfo = best; -+ -+ return 0; -+} -+ -+static int dsi_pll_calc_ddrfreq(unsigned long clk_freq, -+ struct dsi_clock_info *cinfo) -+{ -+ struct dsi_clock_info cur, best; -+ const int use_dss2_fck = 1; -+ unsigned long datafreq; -+ -+ DSSDBG("dsi_pll_calc_ddrfreq\n"); -+ -+ if (clk_freq == dsi.cache_clk_freq && -+ dsi.cache_cinfo.clkin == dss_clk_get_rate(DSS_CLK_FCK2)) { -+ DSSDBG("DSI clock info found from cache\n"); -+ *cinfo = dsi.cache_cinfo; -+ return 0; -+ } -+ -+ datafreq = clk_freq * 4; -+ -+ memset(&best, 0, sizeof(best)); -+ -+ memset(&cur, 0, sizeof(cur)); -+ cur.use_dss2_fck = use_dss2_fck; -+ if (use_dss2_fck) { -+ cur.clkin = dss_clk_get_rate(DSS_CLK_FCK2); -+ cur.highfreq = 0; -+ } else { -+ cur.clkin = dispc_pclk_rate(); -+ if (cur.clkin < 32000000) -+ cur.highfreq = 0; -+ else -+ cur.highfreq = 1; -+ } -+ -+ /* no highfreq: 0.75MHz < Fint = clkin / regn < 2.1MHz */ -+ /* highfreq: 0.75MHz < Fint = clkin / (2*regn) < 2.1MHz */ -+ /* To reduce PLL lock time, keep Fint high (around 2 MHz) */ -+ for (cur.regn = 1; cur.regn < REGN_MAX; ++cur.regn) { -+ if (cur.highfreq == 0) -+ cur.fint = cur.clkin / cur.regn; -+ else -+ cur.fint = cur.clkin / (2 * cur.regn); -+ -+ if (cur.fint > FINT_MAX || cur.fint < FINT_MIN) -+ continue; -+ -+ /* DSIPHY(MHz) = (2 * regm / regn) * (clkin / (highfreq + 1)) */ -+ for (cur.regm = 1; cur.regm < REGM_MAX; ++cur.regm) { -+ unsigned long a, b; -+ -+ a = 2 * cur.regm * (cur.clkin/1000); -+ b = cur.regn * (cur.highfreq + 1); -+ cur.dsiphy = a / b * 1000; -+ -+ if (cur.dsiphy > 1800 * 1000 * 1000) -+ break; -+ -+ if (abs(cur.dsiphy - datafreq) < -+ abs(best.dsiphy - datafreq)) { -+ best = cur; -+ /* DSSDBG("best %ld\n", best.dsiphy); */ -+ } -+ -+ if (cur.dsiphy == datafreq) -+ goto found; -+ } -+ } -+found: -+ /* DSI1_PLL_FCLK(MHz) = DSIPHY(MHz) / regm3 < 173MHz */ -+ /* hardcoded 48MHz for now. what should it be? */ -+ best.regm3 = best.dsiphy / (48000000); -+ if (best.regm3 > REGM3_MAX) -+ best.regm3 = REGM3_MAX; -+ best.dispc_fck = best.dsiphy / best.regm3; -+ -+ /* DSI2_PLL_FCLK(MHz) = DSIPHY(MHz) / regm4 < 173MHz */ -+ /* hardcoded 48MHz for now. what should it be? */ -+ best.regm4 = best.dsiphy / (48000000); -+ if (best.regm4 > REGM4_MAX) -+ best.regm4 = REGM4_MAX; -+ best.dsi_fck = best.dsiphy / best.regm4; -+ -+ if (cinfo) -+ *cinfo = best; -+ -+ dsi.cache_clk_freq = clk_freq; -+ dsi.cache_req_pck = 0; -+ dsi.cache_cinfo = best; -+ -+ return 0; -+} -+ -+int dsi_pll_program(struct dsi_clock_info *cinfo) -+{ -+ int r = 0; -+ u32 l; -+ -+ DSSDBG("dsi_pll_program\n"); -+ -+ enable_clocks(1); -+ dsi_enable_pll_clock(1); -+ -+ dsi.dsiphy = cinfo->dsiphy; -+ dsi.ddr_clk = dsi.dsiphy / 4; -+ dsi.dsi1_pll_fclk = cinfo->dispc_fck; -+ dsi.dsi2_pll_fclk = cinfo->dsi_fck; -+ -+ DSSDBG("DSI Fint %ld\n", cinfo->fint); -+ -+ DSSDBG("clkin (%s) rate %ld, highfreq %d\n", -+ cinfo->use_dss2_fck ? "dss2_fck" : "pclkfree", -+ cinfo->clkin, -+ cinfo->highfreq); -+ -+ /* DSIPHY == CLKIN4DDR */ -+ DSSDBG("DSIPHY = 2 * %d / %d * %lu / %d = %lu\n", -+ cinfo->regm, -+ cinfo->regn, -+ cinfo->clkin, -+ cinfo->highfreq + 1, -+ cinfo->dsiphy); -+ -+ DSSDBG("Data rate on 1 DSI lane %ld Mbps\n", -+ dsi.dsiphy / 1000 / 1000 / 2); -+ -+ DSSDBG("Clock lane freq %ld Hz\n", dsi.ddr_clk); -+ -+ DSSDBG("regm3 = %d, dsi1_pll_fclk = %lu\n", -+ cinfo->regm3, cinfo->dispc_fck); -+ DSSDBG("regm4 = %d, dsi2_pll_fclk = %lu\n", -+ cinfo->regm4, cinfo->dsi_fck); -+ -+ REG_FLD_MOD(DSI_PLL_CONTROL, 0, 0, 0); /* DSI_PLL_AUTOMODE = manual */ -+ -+ l = dsi_read_reg(DSI_PLL_CONFIGURATION1); -+ l = FLD_MOD(l, 1, 0, 0); /* DSI_PLL_STOPMODE */ -+ l = FLD_MOD(l, cinfo->regn - 1, 7, 1); /* DSI_PLL_REGN */ -+ l = FLD_MOD(l, cinfo->regm, 18, 8); /* DSI_PLL_REGM */ -+ l = FLD_MOD(l, cinfo->regm3 - 1, 22, 19); /* DSI_CLOCK_DIV */ -+ l = FLD_MOD(l, cinfo->regm4 - 1, 26, 23); /* DSIPROTO_CLOCK_DIV */ -+ dsi_write_reg(DSI_PLL_CONFIGURATION1, l); -+ -+ l = dsi_read_reg(DSI_PLL_CONFIGURATION2); -+ l = FLD_MOD(l, 7, 4, 1); /* DSI_PLL_FREQSEL */ -+ /* DSI_PLL_CLKSEL */ -+ l = FLD_MOD(l, cinfo->use_dss2_fck ? 0 : 1, 11, 11); -+ l = FLD_MOD(l, cinfo->highfreq, 12, 12); /* DSI_PLL_HIGHFREQ */ -+ l = FLD_MOD(l, 1, 13, 13); /* DSI_PLL_REFEN */ -+ l = FLD_MOD(l, 0, 14, 14); /* DSIPHY_CLKINEN */ -+ l = FLD_MOD(l, 1, 20, 20); /* DSI_HSDIVBYPASS */ -+ dsi_write_reg(DSI_PLL_CONFIGURATION2, l); -+ -+ REG_FLD_MOD(DSI_PLL_GO, 1, 0, 0); /* DSI_PLL_GO */ -+ -+ if (wait_for_bit_change(DSI_PLL_GO, 0, 0) != 0) { -+ DSSERR("dsi pll go bit not going down.\n"); -+ r = -EIO; -+ goto err; -+ } -+ -+ if (wait_for_bit_change(DSI_PLL_STATUS, 1, 1) != 1) { -+ DSSERR("cannot lock PLL\n"); -+ r = -EIO; -+ goto err; -+ } -+ -+ dsi.pll_locked = 1; -+ -+ l = dsi_read_reg(DSI_PLL_CONFIGURATION2); -+ l = FLD_MOD(l, 0, 0, 0); /* DSI_PLL_IDLE */ -+ l = FLD_MOD(l, 0, 5, 5); /* DSI_PLL_PLLLPMODE */ -+ l = FLD_MOD(l, 0, 6, 6); /* DSI_PLL_LOWCURRSTBY */ -+ l = FLD_MOD(l, 0, 7, 7); /* DSI_PLL_TIGHTPHASELOCK */ -+ l = FLD_MOD(l, 0, 8, 8); /* DSI_PLL_DRIFTGUARDEN */ -+ l = FLD_MOD(l, 0, 10, 9); /* DSI_PLL_LOCKSEL */ -+ l = FLD_MOD(l, 1, 13, 13); /* DSI_PLL_REFEN */ -+ l = FLD_MOD(l, 1, 14, 14); /* DSIPHY_CLKINEN */ -+ l = FLD_MOD(l, 0, 15, 15); /* DSI_BYPASSEN */ -+ l = FLD_MOD(l, 1, 16, 16); /* DSS_CLOCK_EN */ -+ l = FLD_MOD(l, 0, 17, 17); /* DSS_CLOCK_PWDN */ -+ l = FLD_MOD(l, 1, 18, 18); /* DSI_PROTO_CLOCK_EN */ -+ l = FLD_MOD(l, 0, 19, 19); /* DSI_PROTO_CLOCK_PWDN */ -+ l = FLD_MOD(l, 0, 20, 20); /* DSI_HSDIVBYPASS */ -+ dsi_write_reg(DSI_PLL_CONFIGURATION2, l); -+ -+ DSSDBG("PLL config done\n"); -+err: -+ enable_clocks(0); -+ dsi_enable_pll_clock(0); -+ -+ return r; -+} -+ -+int dsi_pll_init(int enable_hsclk, int enable_hsdiv) -+{ -+ int r = 0; -+ enum dsi_pll_power_state pwstate; -+ struct dispc_clock_info cinfo; -+ -+ DSSDBG("PLL init\n"); -+ -+ enable_clocks(1); -+ dsi_enable_pll_clock(1); -+ -+ /* configure dispc fck and pixel clock to something sane */ -+ r = dispc_calc_clock_div(1, 48 * 1000 * 1000, &cinfo); -+ if (r) -+ return r; -+ -+ r = dispc_set_clock_div(&cinfo); -+ if (r) { -+ DSSERR("Failed to set basic clocks\n"); -+ return r; -+ } -+ -+ /* PLL does not come out of reset without this... */ -+ dispc_pck_free_enable(1); -+ -+ if (wait_for_bit_change(DSI_PLL_STATUS, 0, 1) != 1) { -+ DSSERR("PLL not coming out of reset.\n"); -+ r = -ENODEV; -+ goto err; -+ } -+ -+ /* ... but if left on, we get problems when planes do not -+ * fill the whole display. No idea about this XXX */ -+ dispc_pck_free_enable(0); -+ -+ if (enable_hsclk && enable_hsdiv) -+ pwstate = DSI_PLL_POWER_ON_ALL; -+ else if (enable_hsclk) -+ pwstate = DSI_PLL_POWER_ON_HSCLK; -+ else if (enable_hsdiv) -+ pwstate = DSI_PLL_POWER_ON_DIV; -+ else -+ pwstate = DSI_PLL_POWER_OFF; -+ -+ r = dsi_pll_power(pwstate); -+ -+ if (r) -+ goto err; -+ -+ enable_clocks(0); -+ dsi_enable_pll_clock(0); -+ -+ DSSDBG("PLL init done\n"); -+ -+ return 0; -+err: -+ enable_clocks(0); -+ dsi_enable_pll_clock(0); -+ return r; -+} -+ -+void dsi_pll_uninit(void) -+{ -+ dsi.pll_locked = 0; -+ dsi_pll_power(DSI_PLL_POWER_OFF); -+ DSSDBG("PLL uninit done\n"); -+} -+ -+unsigned long dsi_get_dsi1_pll_rate(void) -+{ -+ return dsi.dsi1_pll_fclk; -+} -+ -+unsigned long dsi_get_dsi2_pll_rate(void) -+{ -+ return dsi.dsi2_pll_fclk; -+} -+ -+ssize_t dsi_print_clocks(char *buf, ssize_t size) -+{ -+ ssize_t l = 0; -+ int clksel; -+ -+ enable_clocks(1); -+ -+ clksel = REG_GET(DSI_PLL_CONFIGURATION2, 11, 11); -+ -+ l += snprintf(buf + l, size - l, "- dsi -\n"); -+ -+ l += snprintf(buf + l, size - l, "dsi fclk source = %s\n", -+ dss_get_dsi_clk_source() == 0 ? -+ "dss1_alwon_fclk" : "dsi2_pll_fclk"); -+ -+ l += snprintf(buf + l, size - l, "dsi pll source = %s\n", -+ clksel == 0 ? -+ "dss2_alwon_fclk" : "pclkfree"); -+ -+ l += snprintf(buf + l, size - l, -+ "DSIPHY\t\t%lu\nDDR_CLK\t\t%lu\n", -+ dsi.dsiphy, dsi.ddr_clk); -+ -+ l += snprintf(buf + l, size - l, -+ "dsi1_pll_fck\t%lu (%s)\n" -+ "dsi2_pll_fck\t%lu (%s)\n", -+ dsi.dsi1_pll_fclk, -+ dss_get_dispc_clk_source() == 0 ? "off" : "on", -+ dsi.dsi2_pll_fclk, -+ dss_get_dsi_clk_source() == 0 ? "off" : "on"); -+ -+ enable_clocks(0); -+ -+ return l; -+} -+ -+ -+enum dsi_complexio_power_state { -+ DSI_COMPLEXIO_POWER_OFF = 0x0, -+ DSI_COMPLEXIO_POWER_ON = 0x1, -+ DSI_COMPLEXIO_POWER_ULPS = 0x2, -+}; -+ -+static int dsi_complexio_power(enum dsi_complexio_power_state state) -+{ -+ int t = 0; -+ -+ /* PWR_CMD */ -+ REG_FLD_MOD(DSI_COMPLEXIO_CFG1, state, 28, 27); -+ -+ /* PWR_STATUS */ -+ while (FLD_GET(dsi_read_reg(DSI_COMPLEXIO_CFG1), 26, 25) != state) { -+ udelay(1); -+ if (t++ > 1000) { -+ DSSERR("failed to set complexio power state to " -+ "%d\n", state); -+ return -ENODEV; -+ } -+ } -+ -+ return 0; -+} -+ -+static void dsi_complexio_config(struct omap_display *display) -+{ -+ u32 r; -+ -+ int clk_lane = display->hw_config.u.dsi.clk_lane; -+ int data1_lane = display->hw_config.u.dsi.data1_lane; -+ int data2_lane = display->hw_config.u.dsi.data2_lane; -+ int clk_pol = display->hw_config.u.dsi.clk_pol; -+ int data1_pol = display->hw_config.u.dsi.data1_pol; -+ int data2_pol = display->hw_config.u.dsi.data2_pol; -+ -+ r = dsi_read_reg(DSI_COMPLEXIO_CFG1); -+ r = FLD_MOD(r, clk_lane, 2, 0); -+ r = FLD_MOD(r, clk_pol, 3, 3); -+ r = FLD_MOD(r, data1_lane, 6, 4); -+ r = FLD_MOD(r, data1_pol, 7, 7); -+ r = FLD_MOD(r, data2_lane, 10, 8); -+ r = FLD_MOD(r, data2_pol, 11, 11); -+ dsi_write_reg(DSI_COMPLEXIO_CFG1, r); -+ -+ /* The configuration of the DSI complex I/O (number of data lanes, -+ position, differential order) should not be changed while -+ DSS.DSI_CLK_CRTRL[20] LP_CLK_ENABLE bit is set to 1. In order for -+ the hardware to take into account a new configuration of the complex -+ I/O (done in DSS.DSI_COMPLEXIO_CFG1 register), it is recommended to -+ follow this sequence: First set the DSS.DSI_CTRL[0] IF_EN bit to 1, -+ then reset the DSS.DSI_CTRL[0] IF_EN to 0, then set -+ DSS.DSI_CLK_CTRL[20] LP_CLK_ENABLE to 1 and finally set again the -+ DSS.DSI_CTRL[0] IF_EN bit to 1. If the sequence is not followed, the -+ DSI complex I/O configuration is unknown. */ -+ -+ /* -+ REG_FLD_MOD(DSI_CTRL, 1, 0, 0); -+ REG_FLD_MOD(DSI_CTRL, 0, 0, 0); -+ REG_FLD_MOD(DSI_CLK_CTRL, 1, 20, 20); -+ REG_FLD_MOD(DSI_CTRL, 1, 0, 0); -+ */ -+} -+ -+static inline int ns2ddr(int ns) -+{ -+ /* convert time in ns to ddr ticks, rounding up */ -+ return (ns * (dsi.ddr_clk/1000/1000) + 999) / 1000; -+} -+ -+static void dsi_complexio_timings(void) -+{ -+ u32 r; -+ u32 ths_prepare, ths_prepare_ths_zero, ths_trail, ths_exit; -+ u32 tlpx_half, tclk_trail, tclk_zero; -+ u32 tclk_prepare; -+ -+ /* calculate timings */ -+ -+ /* 1 * DDR_CLK = 2 * UI */ -+ -+ /* min 40ns + 4*UI max 85ns + 6*UI */ -+ ths_prepare = ns2ddr(59) + 2; -+ -+ /* min 145ns + 10*UI */ -+ ths_prepare_ths_zero = ns2ddr(145) + 5; -+ -+ /* min max(8*UI, 60ns+4*UI) */ -+ ths_trail = max(4, ns2ddr(60) + 2); -+ -+ /* min 100ns */ -+ ths_exit = ns2ddr(100); -+ -+ /* tlpx min 50n */ -+ tlpx_half = ns2ddr(25); -+ -+ /* min 60ns */ -+ tclk_trail = ns2ddr(60); -+ -+ /* min 38ns, max 95ns */ -+ tclk_prepare = ns2ddr(38); -+ -+ /* min tclk-prepare + tclk-zero = 300ns */ -+ tclk_zero = ns2ddr(300 - 38); -+ -+#ifdef VERBOSE -+ DSSDBG("ths_prepare %d, ths_prepare_ths_zero %d\n", -+ ths_prepare, ths_prepare_ths_zero); -+ DSSDBG("ths_trail %d, ths_exit %d\n", ths_trail, ths_exit); -+ -+ -+ DSSDBG("tlpx_half %d, tclk_trail %d, tclk_zero %d\n", tlpx_half, -+ tclk_trail, tclk_zero); -+ DSSDBG("tclk_prepare %d\n", tclk_prepare); -+#endif -+ -+ /* program timings */ -+ -+ r = dsi_read_reg(DSI_DSIPHY_CFG0); -+ r = FLD_MOD(r, ths_prepare, 31, 24); -+ r = FLD_MOD(r, ths_prepare_ths_zero, 23, 16); -+ r = FLD_MOD(r, ths_trail, 15, 8); -+ r = FLD_MOD(r, ths_exit, 7, 0); -+ dsi_write_reg(DSI_DSIPHY_CFG0, r); -+ -+ r = dsi_read_reg(DSI_DSIPHY_CFG1); -+ r = FLD_MOD(r, tlpx_half, 22, 16); -+ r = FLD_MOD(r, tclk_trail, 15, 8); -+ r = FLD_MOD(r, tclk_zero, 7, 0); -+ dsi_write_reg(DSI_DSIPHY_CFG1, r); -+ -+ r = dsi_read_reg(DSI_DSIPHY_CFG2); -+ r = FLD_MOD(r, tclk_prepare, 7, 0); -+ dsi_write_reg(DSI_DSIPHY_CFG2, r); -+} -+ -+ -+static int dsi_complexio_init(struct omap_display *display) -+{ -+ int r = 0; -+ -+ DSSDBG("dsi_complexio_init\n"); -+ -+ /* CIO_CLK_ICG, enable L3 clk to CIO */ -+ REG_FLD_MOD(DSI_CLK_CTRL, 1, 14, 14); -+ -+ /* A dummy read using the SCP interface to any DSIPHY register is -+ * required after DSIPHY reset to complete the reset of the DSI complex -+ * I/O. */ -+ dsi_read_reg(DSI_DSIPHY_CFG5); -+ -+ if (wait_for_bit_change(DSI_DSIPHY_CFG5, 30, 1) != 1) { -+ DSSERR("ComplexIO PHY not coming out of reset.\n"); -+ r = -ENODEV; -+ goto err; -+ } -+ -+ dsi_complexio_config(display); -+ -+ r = dsi_complexio_power(DSI_COMPLEXIO_POWER_ON); -+ -+ if (r) -+ goto err; -+ -+ if (wait_for_bit_change(DSI_COMPLEXIO_CFG1, 29, 1) != 1) { -+ DSSERR("ComplexIO not coming out of reset.\n"); -+ r = -ENODEV; -+ goto err; -+ } -+ -+ if (wait_for_bit_change(DSI_COMPLEXIO_CFG1, 21, 1) != 1) { -+ DSSERR("ComplexIO LDO power down.\n"); -+ r = -ENODEV; -+ goto err; -+ } -+ -+ dsi_complexio_timings(); -+ -+ /* -+ The configuration of the DSI complex I/O (number of data lanes, -+ position, differential order) should not be changed while -+ DSS.DSI_CLK_CRTRL[20] LP_CLK_ENABLE bit is set to 1. For the -+ hardware to recognize a new configuration of the complex I/O (done -+ in DSS.DSI_COMPLEXIO_CFG1 register), it is recommended to follow -+ this sequence: First set the DSS.DSI_CTRL[0] IF_EN bit to 1, next -+ reset the DSS.DSI_CTRL[0] IF_EN to 0, then set DSS.DSI_CLK_CTRL[20] -+ LP_CLK_ENABLE to 1, and finally, set again the DSS.DSI_CTRL[0] IF_EN -+ bit to 1. If the sequence is not followed, the DSi complex I/O -+ configuration is undetermined. -+ */ -+ dsi_if_enable(1); -+ dsi_if_enable(0); -+ REG_FLD_MOD(DSI_CLK_CTRL, 1, 20, 20); /* LP_CLK_ENABLE */ -+ dsi_if_enable(1); -+ dsi_if_enable(0); -+ -+ DSSDBG("CIO init done\n"); -+err: -+ return r; -+} -+ -+static void dsi_complexio_uninit(void) -+{ -+ dsi_complexio_power(DSI_COMPLEXIO_POWER_OFF); -+} -+ -+ -+ -+static void dsi_config_tx_fifo(enum fifo_size size1, enum fifo_size size2, -+ enum fifo_size size3, enum fifo_size size4) -+{ -+ u32 r = 0; -+ int add = 0; -+ int i; -+ -+ dsi.vc[0].fifo_size = size1; -+ dsi.vc[1].fifo_size = size2; -+ dsi.vc[2].fifo_size = size3; -+ dsi.vc[3].fifo_size = size4; -+ -+ for (i = 0; i < 4; i++) { -+ u8 v; -+ int size = dsi.vc[i].fifo_size; -+ -+ if (add + size > 4) { -+ DSSERR("Illegal FIFO configuration\n"); -+ BUG(); -+ } -+ -+ v = FLD_VAL(add, 2, 0) | FLD_VAL(size, 7, 4); -+ r |= v << (8 * i); -+ /*DSSDBG("TX FIFO vc %d: size %d, add %d\n", i, size, add); */ -+ add += size; -+ } -+ -+ dsi_write_reg(DSI_TX_FIFO_VC_SIZE, r); -+} -+ -+static void dsi_config_rx_fifo(enum fifo_size size1, enum fifo_size size2, -+ enum fifo_size size3, enum fifo_size size4) -+{ -+ u32 r = 0; -+ int add = 0; -+ int i; -+ -+ dsi.vc[0].fifo_size = size1; -+ dsi.vc[1].fifo_size = size2; -+ dsi.vc[2].fifo_size = size3; -+ dsi.vc[3].fifo_size = size4; -+ -+ for (i = 0; i < 4; i++) { -+ u8 v; -+ int size = dsi.vc[i].fifo_size; -+ -+ if (add + size > 4) { -+ DSSERR("Illegal FIFO configuration\n"); -+ BUG(); -+ } -+ -+ v = FLD_VAL(add, 2, 0) | FLD_VAL(size, 7, 4); -+ r |= v << (8 * i); -+ /*DSSDBG("RX FIFO vc %d: size %d, add %d\n", i, size, add); */ -+ add += size; -+ } -+ -+ dsi_write_reg(DSI_RX_FIFO_VC_SIZE, r); -+} -+ -+static int dsi_force_tx_stop_mode_io(void) -+{ -+ u32 r; -+ -+ r = dsi_read_reg(DSI_TIMING1); -+ r = FLD_MOD(r, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */ -+ dsi_write_reg(DSI_TIMING1, r); -+ -+ if (wait_for_bit_change(DSI_TIMING1, 15, 0) != 0) { -+ DSSERR("TX_STOP bit not going down\n"); -+ return -EIO; -+ } -+ -+ return 0; -+} -+ -+static void dsi_vc_print_status(int channel) -+{ -+ u32 r; -+ -+ r = dsi_read_reg(DSI_VC_CTRL(channel)); -+ DSSDBG("vc %d: TX_FIFO_NOT_EMPTY %d, BTA_EN %d, VC_BUSY %d, " -+ "TX_FIFO_FULL %d, RX_FIFO_NOT_EMPTY %d, ", -+ channel, -+ FLD_GET(r, 5, 5), -+ FLD_GET(r, 6, 6), -+ FLD_GET(r, 15, 15), -+ FLD_GET(r, 16, 16), -+ FLD_GET(r, 20, 20)); -+ -+ r = dsi_read_reg(DSI_TX_FIFO_VC_EMPTINESS); -+ DSSDBG("EMPTINESS %d\n", (r >> (8 * channel)) & 0xff); -+} -+ -+static void dsi_vc_config(int channel) -+{ -+ u32 r; -+ -+ DSSDBG("dsi_vc_config %d\n", channel); -+ -+ r = dsi_read_reg(DSI_VC_CTRL(channel)); -+ -+ r = FLD_MOD(r, 0, 1, 1); /* SOURCE, 0 = L4 */ -+ r = FLD_MOD(r, 0, 2, 2); /* BTA_SHORT_EN */ -+ r = FLD_MOD(r, 0, 3, 3); /* BTA_LONG_EN */ -+ r = FLD_MOD(r, 0, 4, 4); /* MODE, 0 = command */ -+ r = FLD_MOD(r, 1, 7, 7); /* CS_TX_EN */ -+ r = FLD_MOD(r, 1, 8, 8); /* ECC_TX_EN */ -+ r = FLD_MOD(r, 0, 9, 9); /* MODE_SPEED, high speed on/off */ -+ -+ r = FLD_MOD(r, 4, 29, 27); /* DMA_RX_REQ_NB = no dma */ -+ r = FLD_MOD(r, 4, 23, 21); /* DMA_TX_REQ_NB = no dma */ -+ -+ dsi_write_reg(DSI_VC_CTRL(channel), r); -+} -+ -+static void dsi_vc_config_vp(int channel) -+{ -+ u32 r; -+ -+ DSSDBG("dsi_vc_config_vp\n"); -+ -+ r = dsi_read_reg(DSI_VC_CTRL(channel)); -+ -+ r = FLD_MOD(r, 1, 1, 1); /* SOURCE, 1 = video port */ -+ r = FLD_MOD(r, 0, 2, 2); /* BTA_SHORT_EN */ -+ r = FLD_MOD(r, 0, 3, 3); /* BTA_LONG_EN */ -+ r = FLD_MOD(r, 0, 4, 4); /* MODE, 0 = command */ -+ r = FLD_MOD(r, 1, 7, 7); /* CS_TX_EN */ -+ r = FLD_MOD(r, 1, 8, 8); /* ECC_TX_EN */ -+ r = FLD_MOD(r, 1, 9, 9); /* MODE_SPEED, high speed on/off */ -+ -+ r = FLD_MOD(r, 4, 29, 27); /* DMA_RX_REQ_NB = no dma */ -+ r = FLD_MOD(r, 4, 23, 21); /* DMA_TX_REQ_NB = no dma */ -+ -+ dsi_write_reg(DSI_VC_CTRL(channel), r); -+} -+ -+ -+static int dsi_vc_enable(int channel, int enable) -+{ -+ DSSDBG("dsi_vc_enable channel %d, enable %d\n", channel, enable); -+ -+ enable = enable ? 1 : 0; -+ -+ REG_FLD_MOD(DSI_VC_CTRL(channel), enable, 0, 0); -+ -+ if (wait_for_bit_change(DSI_VC_CTRL(channel), 0, enable) != enable) { -+ DSSERR("Failed to set dsi_vc_enable to %d\n", enable); -+ return -EIO; -+ } -+ -+ return 0; -+} -+ -+static void dsi_vc_enable_hs(int channel, int enable) -+{ -+ DSSDBG("dsi_vc_enable_hs(%d, %d)\n", channel, enable); -+ -+ dsi_vc_enable(channel, 0); -+ dsi_if_enable(0); -+ -+ REG_FLD_MOD(DSI_VC_CTRL(channel), enable, 9, 9); -+ -+ dsi_vc_enable(channel, 1); -+ dsi_if_enable(1); -+ -+ dsi_force_tx_stop_mode_io(); -+} -+ -+static void dsi_vc_flush_long_data(int channel) -+{ -+ while (REG_GET(DSI_VC_CTRL(channel), 20, 20)) { -+ u32 val; -+ val = dsi_read_reg(DSI_VC_SHORT_PACKET_HEADER(channel)); -+ DSSDBG("\t\tb1 %#02x b2 %#02x b3 %#02x b4 %#02x\n", -+ (val >> 0) & 0xff, -+ (val >> 8) & 0xff, -+ (val >> 16) & 0xff, -+ (val >> 24) & 0xff); -+ } -+} -+ -+static u16 dsi_vc_flush_receive_data(int channel) -+{ -+ /* RX_FIFO_NOT_EMPTY */ -+ while (REG_GET(DSI_VC_CTRL(channel), 20, 20)) { -+ u32 val; -+ u8 dt; -+ val = dsi_read_reg(DSI_VC_SHORT_PACKET_HEADER(channel)); -+ DSSDBG("\trawval %#08x\n", val); -+ dt = FLD_GET(val, 7, 0); -+ if (dt == DSI_DT_RX_ACK_WITH_ERR) { -+ u16 err = FLD_GET(val, 23, 8); -+ DSSERR("\tACK with ERROR: %#x\n", err); -+ if (err & (1 << 9)) -+ DSSERR("\t\tECC multibit\n"); -+ if (err & (1 << 11)) -+ DSSERR("\t\tData type not recognized\n"); -+ if (err & (1 << 12)) -+ DSSERR("\t\tInvalid VC ID\n"); -+ -+ } else if (dt == DSI_DT_RX_SHORT_READ_1) { -+ DSSDBG("\tDCS short response, 1 byte: %#x\n", -+ FLD_GET(val, 23, 8)); -+ return FLD_GET(val, 23, 8); -+ } else if (dt == DSI_DT_RX_SHORT_READ_2) { -+ DSSDBG("\tDCS short response, 2 byte: %#x\n", -+ FLD_GET(val, 23, 8)); -+ return FLD_GET(val, 23, 8); -+ } else if (dt == DSI_DT_RX_DCS_LONG_READ) { -+ DSSDBG("\tDCS long response, len %d\n", -+ FLD_GET(val, 23, 8)); -+ dsi_vc_flush_long_data(channel); -+ } else { -+ DSSERR("\tunknown datatype\n"); -+ } -+ } -+ return 0; -+} -+ -+static int dsi_vc_send_bta(int channel) -+{ -+ unsigned long tmo; -+ -+ /*DSSDBG("dsi_vc_send_bta_sync %d\n", channel); */ -+ -+ if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) { /* RX_FIFO_NOT_EMPTY */ -+ DSSERR("rx fifo not empty when sending BTA, dumping data:\n"); -+ dsi_vc_flush_receive_data(channel); -+ } -+ -+ REG_FLD_MOD(DSI_VC_CTRL(channel), 1, 6, 6); /* BTA_EN */ -+ -+ tmo = jiffies + msecs_to_jiffies(10); -+ while (REG_GET(DSI_VC_CTRL(channel), 6, 6) == 1) { -+ if (time_after(jiffies, tmo)) { -+ DSSERR("Failed to send BTA\n"); -+ return -EIO; -+ } -+ } -+ -+ return 0; -+} -+ -+static int dsi_vc_send_bta_sync(int channel) -+{ -+ int r = 0; -+ -+ init_completion(&dsi.bta_completion); -+ -+ dsi_vc_enable_bta_irq(channel); -+ -+ r = dsi_vc_send_bta(channel); -+ if (r) -+ goto err; -+ -+ if (wait_for_completion_timeout(&dsi.bta_completion, -+ msecs_to_jiffies(500)) == 0) { -+ DSSERR("Failed to receive BTA\n"); -+ r = -EIO; -+ goto err; -+ } -+err: -+ dsi_vc_disable_bta_irq(channel); -+ -+ return r; -+} -+ -+static inline void dsi_vc_write_long_header(int channel, u8 data_type, -+ u16 len, u8 ecc) -+{ -+ u32 val; -+ u8 data_id; -+ -+ /*data_id = data_type | channel << 6; */ -+ data_id = data_type | dsi.vc[channel].dest_per << 6; -+ -+ val = FLD_VAL(data_id, 7, 0) | FLD_VAL(len, 23, 8) | -+ FLD_VAL(ecc, 31, 24); -+ -+ dsi_write_reg(DSI_VC_LONG_PACKET_HEADER(channel), val); -+} -+ -+static inline void dsi_vc_write_long_payload(int channel, -+ u8 b1, u8 b2, u8 b3, u8 b4) -+{ -+ u32 val; -+ -+ val = b4 << 24 | b3 << 16 | b2 << 8 | b1 << 0; -+ -+/* DSSDBG("\twriting %02x, %02x, %02x, %02x (%#010x)\n", -+ b1, b2, b3, b4, val); */ -+ -+ dsi_write_reg(DSI_VC_LONG_PACKET_PAYLOAD(channel), val); -+} -+ -+static int dsi_vc_send_long(int channel, u8 data_type, u8 *data, u16 len, -+ u8 ecc) -+{ -+ /*u32 val; */ -+ int i; -+ u8 *p; -+ int r = 0; -+ u8 b1, b2, b3, b4; -+ -+ /*DSSDBG("dsi_vc_send_long, %d bytes\n", len); */ -+ -+ /* len + header */ -+ if (dsi.vc[channel].fifo_size * 32 * 4 < len + 4) { -+ DSSERR("unable to send long packet: packet too long.\n"); -+ return -EINVAL; -+ } -+ -+ dsi_vc_write_long_header(channel, data_type, len, ecc); -+ -+ /*dsi_vc_print_status(0); */ -+ -+ p = data; -+ for (i = 0; i < len >> 2; i++) { -+ /*DSSDBG("\tsending full packet %d\n", i); */ -+ /*dsi_vc_print_status(0); */ -+ -+ b1 = *p++; -+ b2 = *p++; -+ b3 = *p++; -+ b4 = *p++; -+ -+ dsi_vc_write_long_payload(channel, b1, b2, b3, b4); -+ } -+ -+ i = len % 4; -+ if (i) { -+ b1 = 0; b2 = 0; b3 = 0; -+ -+ /*DSSDBG("\tsending remainder bytes %d\n", i); */ -+ -+ switch (i) { -+ case 3: -+ b1 = *p++; -+ b2 = *p++; -+ b3 = *p++; -+ break; -+ case 2: -+ b1 = *p++; -+ b2 = *p++; -+ break; -+ case 1: -+ b1 = *p++; -+ break; -+ } -+ -+ dsi_vc_write_long_payload(channel, b1, b2, b3, 0); -+ } -+ -+ return r; -+} -+ -+static int dsi_vc_send_short(int channel, u8 data_type, u16 data, u8 ecc) -+{ -+ u32 r; -+ u8 data_id; -+/* -+ DSSDBG("dsi_vc_send_short(ch%d, dt %#x, b1 %#x, b2 %#x)\n", -+ channel, -+ data_type, data & 0xff, (data >> 8) & 0xff); -+*/ -+ if (FLD_GET(dsi_read_reg(DSI_VC_CTRL(channel)), 16, 16)) { -+ DSSERR("ERROR FIFO FULL, aborting transfer\n"); -+ return -EINVAL; -+ } -+ -+ data_id = data_type | channel << 6; -+ -+ r = (data_id << 0) | (data << 8) | (ecc << 24); -+ -+ dsi_write_reg(DSI_VC_SHORT_PACKET_HEADER(channel), r); -+ -+ return 0; -+} -+ -+int dsi_vc_send_null(int channel) -+{ -+ u8 nullpkg[] = {0, 0, 0, 0}; -+ return dsi_vc_send_long(0, DSI_DT_NULL_PACKET, nullpkg, 4, 0); -+} -+EXPORT_SYMBOL(dsi_vc_send_null); -+ -+int dsi_vc_dcs_write_nosync(int channel, u8 *data, int len) -+{ -+ int r; -+ -+ BUG_ON(len == 0); -+ -+ if (len == 1) { -+ r = dsi_vc_send_short(channel, DSI_DT_DCS_SHORT_WRITE_0, -+ data[0], 0); -+ } else if (len == 2) { -+ r = dsi_vc_send_short(channel, DSI_DT_DCS_SHORT_WRITE_1, -+ data[0] | (data[1] << 8), 0); -+ } else { -+ /* 0x39 = DCS Long Write */ -+ r = dsi_vc_send_long(channel, DSI_DT_DCS_LONG_WRITE, -+ data, len, 0); -+ } -+ -+ return r; -+} -+EXPORT_SYMBOL(dsi_vc_dcs_write_nosync); -+ -+int dsi_vc_dcs_write(int channel, u8 *data, int len) -+{ -+ int r; -+ -+ r = dsi_vc_dcs_write_nosync(channel, data, len); -+ if (r) -+ return r; -+ -+ /* Some devices need time to process the msg in low power mode. -+ This also makes the write synchronous, and checks that -+ the peripheral is still alive */ -+ r = dsi_vc_send_bta_sync(channel); -+ -+ return r; -+} -+EXPORT_SYMBOL(dsi_vc_dcs_write); -+ -+int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen) -+{ -+ u32 val; -+ u8 dt; -+ int debug = 0; -+ -+ if (debug) -+ DSSDBG("dsi_vc_dcs_read\n"); -+ -+ dsi_vc_send_short(channel, DSI_DT_DCS_READ, dcs_cmd, 0); -+ -+ dsi_vc_send_bta_sync(channel); -+ -+ val = dsi_read_reg(DSI_VC_SHORT_PACKET_HEADER(channel)); -+ if (debug) -+ DSSDBG("\trawval %#08x\n", val); -+ dt = FLD_GET(val, 7, 0); -+ if (dt == DSI_DT_RX_ACK_WITH_ERR) { -+ u16 err = FLD_GET(val, 23, 8); -+ DSSERR("\tACK with ERROR: %#x\n", err); -+ if (err & (1 << 9)) -+ DSSERR("\t\tECC multibit\n"); -+ if (err & (1 << 11)) -+ DSSERR("\t\tData type not recognized\n"); -+ if (err & (1 << 12)) -+ DSSERR("\t\tInvalid VC ID\n"); -+ return -1; -+ -+ } else if (dt == DSI_DT_RX_SHORT_READ_1) { -+ u8 data = FLD_GET(val, 15, 8); -+ if (debug) -+ DSSDBG("\tDCS short response, 1 byte: %#x\n", data); -+ -+ if (buflen < 1) -+ return -1; -+ -+ buf[0] = data; -+ -+ return 1; -+ } else if (dt == DSI_DT_RX_SHORT_READ_2) { -+ u16 data = FLD_GET(val, 23, 8); -+ if (debug) -+ DSSDBG("\tDCS short response, 2 byte: %#x\n", data); -+ -+ if (buflen < 2) -+ return -1; -+ -+ buf[0] = data & 0xff; -+ buf[1] = (data >> 8) & 0xff; -+ -+ return 2; -+ } else if (dt == DSI_DT_RX_DCS_LONG_READ) { -+ int x; -+ int len = FLD_GET(val, 23, 8); -+ if (debug) -+ DSSDBG("\tDCS long response, len %d\n", len); -+ -+ if (len > buflen) -+ return -1; -+ -+ x = 0; -+ while (x < len) { -+ val = dsi_read_reg(DSI_VC_SHORT_PACKET_HEADER(channel)); -+ if (debug) -+ DSSDBG("\t\tb1 %#02x b2 %#02x b3 %#02x b4 " -+ "%#02x\n", -+ (val >> 0) & 0xff, -+ (val >> 8) & 0xff, -+ (val >> 16) & 0xff, -+ (val >> 24) & 0xff); -+ -+ if (x < len) -+ buf[x++] = (val >> 0) & 0xff; -+ if (x < len) -+ buf[x++] = (val >> 8) & 0xff; -+ if (x < len) -+ buf[x++] = (val >> 16) & 0xff; -+ if (x < len) -+ buf[x++] = (val >> 24) & 0xff; -+ } -+ -+ return len; -+ } else { -+ DSSERR("\tunknown datatype\n"); -+ return -1; -+ } -+} -+EXPORT_SYMBOL(dsi_vc_dcs_read); -+ -+ -+int dsi_vc_set_max_rx_packet_size(int channel, u16 len) -+{ -+ return dsi_vc_send_short(channel, DSI_DT_SET_MAX_RET_PKG_SIZE, -+ len, 0); -+} -+EXPORT_SYMBOL(dsi_vc_set_max_rx_packet_size); -+ -+ -+static int dsi_set_lp_rx_timeout(int ns, int x4, int x16) -+{ -+ u32 r; -+ unsigned long fck; -+ int ticks; -+ -+ /* ticks in DSI_FCK */ -+ -+ fck = dsi_fclk_rate(); -+ ticks = (fck / 1000 / 1000) * ns / 1000; -+ -+ if (ticks > 0x1fff) { -+ DSSERR("LP_TX_TO too high\n"); -+ return -EINVAL; -+ } -+ -+ r = dsi_read_reg(DSI_TIMING2); -+ r = FLD_MOD(r, 1, 15, 15); /* LP_RX_TO */ -+ r = FLD_MOD(r, x16, 14, 14); /* LP_RX_TO_X16 */ -+ r = FLD_MOD(r, x4, 13, 13); /* LP_RX_TO_X4 */ -+ r = FLD_MOD(r, ticks, 12, 0); /* LP_RX_COUNTER */ -+ dsi_write_reg(DSI_TIMING2, r); -+ -+ DSSDBG("LP_RX_TO %ld ns (%#x ticks)\n", -+ (ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1) * 1000) / -+ (fck / 1000 / 1000), -+ ticks); -+ -+ return 0; -+} -+ -+static int dsi_set_ta_timeout(int ns, int x8, int x16) -+{ -+ u32 r; -+ unsigned long fck; -+ int ticks; -+ -+ /* ticks in DSI_FCK */ -+ -+ fck = dsi_fclk_rate(); -+ ticks = (fck / 1000 / 1000) * ns / 1000; -+ -+ if (ticks > 0x1fff) { -+ DSSERR("TA_TO too high\n"); -+ return -EINVAL; -+ } -+ -+ r = dsi_read_reg(DSI_TIMING1); -+ r = FLD_MOD(r, 1, 31, 31); /* TA_TO */ -+ r = FLD_MOD(r, x16, 30, 30); /* TA_TO_X16 */ -+ r = FLD_MOD(r, x8, 29, 29); /* TA_TO_X8 */ -+ r = FLD_MOD(r, ticks, 28, 16); /* TA_TO_COUNTER */ -+ dsi_write_reg(DSI_TIMING1, r); -+ -+ DSSDBG("TA_TO %ld ns (%#x ticks)\n", -+ (ticks * (x16 ? 16 : 1) * (x8 ? 8 : 1) * 1000) / -+ (fck / 1000 / 1000), -+ ticks); -+ -+ return 0; -+} -+ -+static int dsi_set_stop_state_counter(int ns, int x4, int x16) -+{ -+ u32 r; -+ unsigned long fck; -+ int ticks; -+ -+ /* ticks in DSI_FCK */ -+ -+ fck = dsi_fclk_rate(); -+ ticks = (fck / 1000 / 1000) * ns / 1000; -+ -+ if (ticks > 0x1fff) { -+ DSSERR("STOP_STATE_COUNTER_IO too high\n"); -+ return -EINVAL; -+ } -+ -+ r = dsi_read_reg(DSI_TIMING1); -+ r = FLD_MOD(r, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */ -+ r = FLD_MOD(r, x16, 14, 14); /* STOP_STATE_X16_IO */ -+ r = FLD_MOD(r, x4, 13, 13); /* STOP_STATE_X4_IO */ -+ r = FLD_MOD(r, ticks, 12, 0); /* STOP_STATE_COUNTER_IO */ -+ dsi_write_reg(DSI_TIMING1, r); -+ -+ DSSDBG("STOP_STATE_COUNTER %ld ns (%#x ticks)\n", -+ (ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1) * 1000) / -+ (fck / 1000 / 1000), -+ ticks); -+ -+ return 0; -+} -+ -+static int dsi_set_hs_tx_timeout(int ns, int x4, int x16) -+{ -+ u32 r; -+ unsigned long fck; -+ int ticks; -+ -+ /* ticks in TxByteClkHS */ -+ -+ fck = dsi.ddr_clk / 4; -+ ticks = (fck / 1000 / 1000) * ns / 1000; -+ -+ if (ticks > 0x1fff) { -+ DSSERR("HS_TX_TO too high\n"); -+ return -EINVAL; -+ } -+ -+ r = dsi_read_reg(DSI_TIMING2); -+ r = FLD_MOD(r, 1, 31, 31); /* HS_TX_TO */ -+ r = FLD_MOD(r, x16, 30, 30); /* HS_TX_TO_X16 */ -+ r = FLD_MOD(r, x4, 29, 29); /* HS_TX_TO_X8 (4 really) */ -+ r = FLD_MOD(r, ticks, 28, 16); /* HS_TX_TO_COUNTER */ -+ dsi_write_reg(DSI_TIMING2, r); -+ -+ DSSDBG("HS_TX_TO %ld ns (%#x ticks)\n", -+ (ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1) * 1000) / -+ (fck / 1000 / 1000), -+ ticks); -+ -+ return 0; -+} -+static int dsi_proto_config(struct omap_display *display) -+{ -+ u32 r; -+ int buswidth = 0; -+ -+ dsi_config_tx_fifo(DSI_FIFO_SIZE_128, -+ DSI_FIFO_SIZE_0, -+ DSI_FIFO_SIZE_0, -+ DSI_FIFO_SIZE_0); -+ -+ dsi_config_rx_fifo(DSI_FIFO_SIZE_128, -+ DSI_FIFO_SIZE_0, -+ DSI_FIFO_SIZE_0, -+ DSI_FIFO_SIZE_0); -+ -+ /* XXX what values for the timeouts? */ -+ dsi_set_stop_state_counter(1000, 0, 0); -+ -+ dsi_set_ta_timeout(50000, 1, 1); -+ -+ /* 3000ns * 16 */ -+ dsi_set_lp_rx_timeout(3000, 0, 1); -+ -+ /* 10000ns * 4 */ -+ dsi_set_hs_tx_timeout(10000, 1, 0); -+ -+ switch (display->ctrl->pixel_size) { -+ case 16: -+ buswidth = 0; -+ break; -+ case 18: -+ buswidth = 1; -+ break; -+ case 24: -+ buswidth = 2; -+ break; -+ default: -+ BUG(); -+ } -+ -+ r = dsi_read_reg(DSI_CTRL); -+ r = FLD_MOD(r, 1, 1, 1); /* CS_RX_EN */ -+ r = FLD_MOD(r, 1, 2, 2); /* ECC_RX_EN */ -+ r = FLD_MOD(r, 1, 3, 3); /* TX_FIFO_ARBITRATION */ -+ /* XXX what should the ratio be */ -+ r = FLD_MOD(r, 0, 4, 4); /* VP_CLK_RATIO, VP_PCLK = VP_CLK/2 */ -+ r = FLD_MOD(r, buswidth, 7, 6); /* VP_DATA_BUS_WIDTH */ -+ r = FLD_MOD(r, 0, 8, 8); /* VP_CLK_POL */ -+ r = FLD_MOD(r, 2, 13, 12); /* LINE_BUFFER, 2 lines */ -+ r = FLD_MOD(r, 1, 14, 14); /* TRIGGER_RESET_MODE */ -+ r = FLD_MOD(r, 1, 19, 19); /* EOT_ENABLE */ -+ r = FLD_MOD(r, 1, 24, 24); /* DCS_CMD_ENABLE */ -+ r = FLD_MOD(r, 0, 25, 25); /* DCS_CMD_CODE, 1=start, 0=continue */ -+ -+ dsi_write_reg(DSI_CTRL, r); -+ -+ /* we configure vc0 for L4 communication, and -+ * vc1 for dispc */ -+ dsi_vc_config(0); -+ dsi_vc_config_vp(1); -+ -+ /* set all vc targets to peripheral 0 */ -+ dsi.vc[0].dest_per = 0; -+ dsi.vc[1].dest_per = 0; -+ dsi.vc[2].dest_per = 0; -+ dsi.vc[3].dest_per = 0; -+ -+ return 0; -+} -+ -+static void dsi_proto_timings(void) -+{ -+ int tlpx_half, tclk_zero, tclk_prepare, tclk_trail; -+ int tclk_pre, tclk_post; -+ int ddr_clk_pre, ddr_clk_post; -+ u32 r; -+ -+ r = dsi_read_reg(DSI_DSIPHY_CFG1); -+ tlpx_half = FLD_GET(r, 22, 16); -+ tclk_trail = FLD_GET(r, 15, 8); -+ tclk_zero = FLD_GET(r, 7, 0); -+ -+ r = dsi_read_reg(DSI_DSIPHY_CFG2); -+ tclk_prepare = FLD_GET(r, 7, 0); -+ -+ /* min 8*UI */ -+ tclk_pre = 20; -+ /* min 60ns + 52*UI */ -+ tclk_post = ns2ddr(60) + 26; -+ -+ ddr_clk_pre = (tclk_pre + tlpx_half*2 + tclk_zero + tclk_prepare) / 4; -+ ddr_clk_post = (tclk_post + tclk_trail) / 4; -+ -+ r = dsi_read_reg(DSI_CLK_TIMING); -+ r = FLD_MOD(r, ddr_clk_pre, 15, 8); -+ r = FLD_MOD(r, ddr_clk_post, 7, 0); -+ dsi_write_reg(DSI_CLK_TIMING, r); -+ -+#ifdef VERBOSE -+ DSSDBG("ddr_clk_pre %d, ddr_clk_post %d\n", -+ ddr_clk_pre, -+ ddr_clk_post); -+#endif -+} -+ -+ -+#define DSI_DECL_VARS \ -+ int __dsi_cb = 0; u32 __dsi_cv = 0; -+ -+#define DSI_FLUSH(ch) \ -+ if (__dsi_cb > 0) { \ -+ /*DSSDBG("sending long packet %#010x\n", __dsi_cv);*/ \ -+ dsi_write_reg(DSI_VC_LONG_PACKET_PAYLOAD(ch), __dsi_cv); \ -+ __dsi_cb = __dsi_cv = 0; \ -+ } -+ -+#define DSI_PUSH(ch, data) \ -+ do { \ -+ __dsi_cv |= (data) << (__dsi_cb * 8); \ -+ /*DSSDBG("cv = %#010x, cb = %d\n", __dsi_cv, __dsi_cb);*/ \ -+ if (++__dsi_cb > 3) \ -+ DSI_FLUSH(ch); \ -+ } while (0) -+ -+static int dsi_update_screen_l4(struct omap_display *display, -+ int x, int y, int w, int h) -+{ -+ /* Note: supports only 24bit colors in 32bit container */ -+ int first = 1; -+ int fifo_stalls = 0; -+ int max_dsi_packet_size; -+ int max_data_per_packet; -+ int max_pixels_per_packet; -+ int pixels_left; -+ int bytespp = 3; -+ int scr_width; -+ u32 *data; -+ int start_offset; -+ int horiz_inc; -+ int current_x; -+ struct omap_overlay *ovl; -+ -+ debug_irq = 0; -+ -+ DSSDBG("dsi_update_screen_l4 (%d,%d %dx%d)\n", -+ x, y, w, h); -+ -+ ovl = &display->manager->overlays[0]; -+ -+ if (ovl->info.color_mode != OMAP_DSS_COLOR_RGB24U) -+ return -EINVAL; -+ -+ if (display->ctrl->pixel_size != 24) -+ return -EINVAL; -+ -+ enable_clocks(1); -+ dsi_enable_pll_clock(1); -+ -+ scr_width = ovl->info.screen_width; -+ data = ovl->info.vaddr; -+ -+ start_offset = scr_width * y + x; -+ horiz_inc = scr_width - w; -+ current_x = x; -+ -+ /* We need header(4) + DCSCMD(1) + pixels(numpix*bytespp) bytes -+ * in fifo */ -+ -+ /* When using CPU, max long packet size is TX buffer size */ -+ max_dsi_packet_size = dsi.vc[0].fifo_size * 32 * 4; -+ -+ /* we seem to get better perf if we divide the tx fifo to half, -+ and while the other half is being sent, we fill the other half -+ max_dsi_packet_size /= 2; */ -+ -+ max_data_per_packet = max_dsi_packet_size - 4 - 1; -+ -+ max_pixels_per_packet = max_data_per_packet / bytespp; -+ -+ DSSDBG("max_pixels_per_packet %d\n", max_pixels_per_packet); -+ -+ display->ctrl->setup_update(display, x, y, w, h); -+ -+ pixels_left = w * h; -+ -+ DSSDBG("total pixels %d\n", pixels_left); -+ -+ data += start_offset; -+ -+ dsi.update_region.x = x; -+ dsi.update_region.y = y; -+ dsi.update_region.w = w; -+ dsi.update_region.h = h; -+ dsi.update_region.bytespp = bytespp; -+ -+ perf_mark_start(); -+ -+ while (pixels_left > 0) { -+ /* 0x2c = write_memory_start */ -+ /* 0x3c = write_memory_continue */ -+ u8 dcs_cmd = first ? 0x2c : 0x3c; -+ int pixels; -+ DSI_DECL_VARS; -+ first = 0; -+ -+#if 1 -+ /* using fifo not empty */ -+ /* TX_FIFO_NOT_EMPTY */ -+ while (FLD_GET(dsi_read_reg(DSI_VC_CTRL(0)), 5, 5)) { -+ udelay(1); -+ fifo_stalls++; -+ if (fifo_stalls > 0xfffff) { -+ DSSERR("fifo stalls overflow, pixels left %d\n", -+ pixels_left); -+ dsi_if_enable(0); -+ enable_clocks(0); -+ return -EIO; -+ } -+ } -+#elif 1 -+ /* using fifo emptiness */ -+ while ((REG_GET(DSI_TX_FIFO_VC_EMPTINESS, 7, 0)+1)*4 < -+ max_dsi_packet_size) { -+ fifo_stalls++; -+ if (fifo_stalls > 0xfffff) { -+ DSSERR("fifo stalls overflow, pixels left %d\n", -+ pixels_left); -+ dsi_if_enable(0); -+ enable_clocks(0); -+ return -EIO; -+ } -+ } -+#else -+ while ((REG_GET(DSI_TX_FIFO_VC_EMPTINESS, 7, 0)+1)*4 == 0) { -+ fifo_stalls++; -+ if (fifo_stalls > 0xfffff) { -+ DSSERR("fifo stalls overflow, pixels left %d\n", -+ pixels_left); -+ dsi_if_enable(0); -+ enable_clocks(0); -+ return -EIO; -+ } -+ } -+#endif -+ pixels = min(max_pixels_per_packet, pixels_left); -+ -+ pixels_left -= pixels; -+ -+ dsi_vc_write_long_header(0, DSI_DT_DCS_LONG_WRITE, -+ 1 + pixels * bytespp, 0); -+ -+ DSI_PUSH(0, dcs_cmd); -+ -+ while (pixels-- > 0) { -+ u32 pix = *data++; -+ -+ DSI_PUSH(0, (pix >> 16) & 0xff); -+ DSI_PUSH(0, (pix >> 8) & 0xff); -+ DSI_PUSH(0, (pix >> 0) & 0xff); -+ -+ current_x++; -+ if (current_x == x+w) { -+ current_x = x; -+ data += horiz_inc; -+ } -+ } -+ -+ DSI_FLUSH(0); -+ } -+ -+ perf_show("L4"); -+ -+ enable_clocks(0); -+ dsi_enable_pll_clock(0); -+ -+ return 0; -+} -+ -+#if 0 -+static void dsi_clear_screen_l4(struct omap_display *display, -+ int x, int y, int w, int h) -+{ -+ int first = 1; -+ int fifo_stalls = 0; -+ int max_dsi_packet_size; -+ int max_data_per_packet; -+ int max_pixels_per_packet; -+ int pixels_left; -+ int bytespp = 3; -+ int pixnum; -+ -+ debug_irq = 0; -+ -+ DSSDBG("dsi_clear_screen_l4 (%d,%d %dx%d)\n", -+ x, y, w, h); -+ -+ if (display->ctrl->bpp != 24) -+ return -EINVAL; -+ -+ /* We need header(4) + DCSCMD(1) + pixels(numpix*bytespp) -+ * bytes in fifo */ -+ -+ /* When using CPU, max long packet size is TX buffer size */ -+ max_dsi_packet_size = dsi.vc[0].fifo_size * 32 * 4; -+ -+ max_data_per_packet = max_dsi_packet_size - 4 - 1; -+ -+ max_pixels_per_packet = max_data_per_packet / bytespp; -+ -+ enable_clocks(1); -+ -+ display->ctrl->setup_update(display, x, y, w, h); -+ -+ pixels_left = w * h; -+ -+ dsi.update_region.x = x; -+ dsi.update_region.y = y; -+ dsi.update_region.w = w; -+ dsi.update_region.h = h; -+ dsi.update_region.bytespp = bytespp; -+ -+ start_measuring(); -+ -+ pixnum = 0; -+ -+ while (pixels_left > 0) { -+ /* 0x2c = write_memory_start */ -+ /* 0x3c = write_memory_continue */ -+ u8 dcs_cmd = first ? 0x2c : 0x3c; -+ int pixels; -+ DSI_DECL_VARS; -+ first = 0; -+ -+ /* TX_FIFO_NOT_EMPTY */ -+ while (FLD_GET(dsi_read_reg(DSI_VC_CTRL(0)), 5, 5)) { -+ fifo_stalls++; -+ if (fifo_stalls > 0xfffff) { -+ DSSERR("fifo stalls overflow\n"); -+ dsi_if_enable(0); -+ enable_clocks(0); -+ return; -+ } -+ } -+ -+ pixels = min(max_pixels_per_packet, pixels_left); -+ -+ pixels_left -= pixels; -+ -+ dsi_vc_write_long_header(0, DSI_DT_DCS_LONG_WRITE, -+ 1 + pixels * bytespp, 0); -+ -+ DSI_PUSH(0, dcs_cmd); -+ -+ while (pixels-- > 0) { -+ u32 pix; -+ -+ pix = 0x000000; -+ -+ DSI_PUSH(0, (pix >> 16) & 0xff); -+ DSI_PUSH(0, (pix >> 8) & 0xff); -+ DSI_PUSH(0, (pix >> 0) & 0xff); -+ } -+ -+ DSI_FLUSH(0); -+ } -+ -+ enable_clocks(0); -+ -+ end_measuring("L4 CLEAR"); -+} -+#endif -+ -+static int dsi_wait_for_framedone(int stop_update) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&dsi.update_lock, flags); -+ if (dsi.update_ongoing) { -+ long wait = msecs_to_jiffies(1000); -+ dsi.update_syncers++; -+ if (stop_update) -+ dsi.update_mode = OMAP_DSS_UPDATE_DISABLED; -+ spin_unlock_irqrestore(&dsi.update_lock, flags); -+ wait = wait_for_completion_timeout(&dsi.update_completion, -+ wait); -+ if (wait == 0) { -+ DSSERR("timeout waiting sync\n"); -+ return -ETIME; -+ } -+ } else { -+ spin_unlock_irqrestore(&dsi.update_lock, flags); -+ } -+ -+ return 0; -+} -+ -+static void dsi_setup_update_dispc(struct omap_display *display, -+ int x, int y, int w, int h) -+{ -+ int bytespp = 3; -+ -+ DSSDBG("dsi_setup_update_dispc(%d,%d %dx%d)\n", -+ x, y, w, h); -+ -+ dsi.update_region.display = display; -+ dsi.update_region.x = x; -+ dsi.update_region.y = y; -+ dsi.update_region.w = w; -+ dsi.update_region.h = h; -+ dsi.update_region.bytespp = bytespp; -+ -+ enable_clocks(1); -+ -+ dispc_setup_partial_planes(display, &x, &y, &w, &h); -+ -+ dispc_set_lcd_size(w, h); -+ -+ enable_clocks(0); -+} -+ -+static void dsi_update_screen_dispc(struct omap_display *display) -+{ -+ int bytespp = 3; -+ int total_len; -+ int line_packet_len; -+ int x, y, w, h; -+ u32 l; -+ -+ x = dsi.update_region.x; -+ y = dsi.update_region.y; -+ w = dsi.update_region.w; -+ h = dsi.update_region.h; -+ -+ if (dsi.user_update_mode != OMAP_DSS_UPDATE_AUTO) -+ DSSDBG("dsi_update_screen_dispc(%d,%d %dx%d)\n", -+ x, y, w, h); -+ -+ enable_clocks(1); -+ dsi_enable_pll_clock(1); -+ -+ /* TODO: one packet could be longer, I think? Max is the line buffer */ -+ line_packet_len = w * bytespp + 1; /* 1 byte for DCS cmd */ -+ total_len = line_packet_len * h; -+ -+ display->ctrl->setup_update(display, x, y, w, h); -+ -+ if (0) -+ dsi_vc_print_status(1); -+ -+ perf_mark_start(); -+ -+ l = FLD_VAL(total_len, 23, 0); /* TE_SIZE */ -+ dsi_write_reg(DSI_VC_TE(1), l); -+ -+ dsi_vc_write_long_header(1, DSI_DT_DCS_LONG_WRITE, line_packet_len, 0); -+ -+ if (dsi.use_te) -+ l = FLD_MOD(l, 1, 30, 30); /* TE_EN */ -+ else -+ l = FLD_MOD(l, 1, 31, 31); /* TE_START */ -+ dsi_write_reg(DSI_VC_TE(1), l); -+ -+ dispc_enable_lcd_out(1); -+ -+ if (dsi.use_te) -+ dsi_vc_send_bta(1); -+} -+ -+static void framedone_callback(void *data, u32 mask) -+{ -+ if (dsi.framedone_scheduled) { -+ DSSERR("Framedone already scheduled. Bogus FRAMEDONE IRQ?\n"); -+ return; -+ } -+ -+ dsi.framedone_scheduled = 1; -+ -+ /* We get FRAMEDONE when DISPC has finished sending pixels and turns -+ * itself off. However, DSI still has the pixels in its buffers, and -+ * is sending the data. Thus we have to wait until we can do a new -+ * transfer or turn the clocks off. We do that in a separate work -+ * func. */ -+ /* XXX When using auto update and delay value 0, the kernel seems to be -+ * very relaxed about when to call our callback. It may take a second. -+ * Thus we use a delay of 1 */ -+ if (dsi.update_mode == OMAP_DSS_UPDATE_AUTO) -+ schedule_delayed_work(&dsi.framedone_work, 1); -+ else -+ schedule_delayed_work(&dsi.framedone_work, 0); -+} -+ -+static void framedone_worker(struct work_struct *work) -+{ -+ unsigned long flags; -+ u32 l; -+ unsigned long tmo; -+ int i = 0; -+ -+ l = REG_GET(DSI_VC_TE(1), 23, 0); /* TE_SIZE */ -+ -+ /* There shouldn't be much stuff in DSI buffers, if any, so we'll -+ * just busyloop */ -+ if (l > 0) { -+ tmo = jiffies + msecs_to_jiffies(50); -+ while (REG_GET(DSI_VC_TE(1), 23, 0) > 0) { /* TE_SIZE */ -+ i++; -+ if (time_after(jiffies, tmo)) { -+ DSSERR("timeout waiting TE_SIZE to zero\n"); -+ break; -+ } -+ cpu_relax(); -+ } -+ } -+ -+ if (REG_GET(DSI_VC_TE(1), 30, 30)) -+ DSSERR("TE_EN not zero\n"); -+ -+ if (REG_GET(DSI_VC_TE(1), 31, 31)) -+ DSSERR("TE_START not zero\n"); -+ -+ spin_lock_irqsave(&dsi.update_lock, flags); -+ if (dsi.update_ongoing == 0) { -+ spin_unlock_irqrestore(&dsi.update_lock, flags); -+ DSSERR("framedone irq without update request\n"); -+ return; -+ } -+ spin_unlock_irqrestore(&dsi.update_lock, flags); -+ -+ perf_show("DISPC"); -+ -+ if (dsi.user_update_mode != OMAP_DSS_UPDATE_AUTO) -+ DSSDBG("FRAMEDONE\n"); -+ -+#if 0 -+ if (l) -+ DSSWARN("FRAMEDONE irq too early, %d bytes, %d loops\n", l, i); -+#else -+ if (l > 1024*3) -+ DSSWARN("FRAMEDONE irq too early, %d bytes, %d loops\n", l, i); -+#endif -+ -+#ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC -+ dispc_fake_vsync_irq(); -+#endif -+ enable_clocks(0); -+ dsi_enable_pll_clock(0); -+ -+ dsi.framedone_scheduled = 0; -+ -+ spin_lock_irqsave(&dsi.update_lock, flags); -+ -+ if (dsi.update_mode != OMAP_DSS_UPDATE_AUTO) -+ dsi.update_ongoing = 0; -+ -+ while (dsi.update_syncers > 0) { -+ complete(&dsi.update_completion); -+ --dsi.update_syncers; -+ } -+ -+ if (dsi.update_mode == OMAP_DSS_UPDATE_AUTO) { -+ spin_unlock_irqrestore(&dsi.update_lock, flags); -+ dsi_update_screen_dispc(dsi.update_region.display); -+ } else { -+ spin_unlock_irqrestore(&dsi.update_lock, flags); -+ } -+} -+ -+static void dsi_start_auto_update(struct omap_display *display) -+{ -+ unsigned long flags; -+ int bytespp = 3; -+ -+ DSSDBG("starting auto update\n"); -+ -+ dsi.update_region.display = display; -+ dsi.update_region.x = 0; -+ dsi.update_region.y = 0; -+ dsi.update_region.w = display->panel->timings.x_res; -+ dsi.update_region.h = display->panel->timings.y_res; -+ dsi.update_region.bytespp = bytespp; -+ -+ enable_clocks(1); -+ dsi_enable_pll_clock(1); -+ -+ dispc_set_lcd_size(display->panel->timings.x_res, -+ display->panel->timings.y_res); -+ -+ spin_lock_irqsave(&dsi.update_lock, flags); -+ dsi.update_ongoing = 1; -+ spin_unlock_irqrestore(&dsi.update_lock, flags); -+ dsi_update_screen_dispc(display); -+} -+ -+static void dsi_stop_auto_update(void) -+{ -+ DSSDBG("waiting for display to finish.\n"); -+ dsi_wait_for_framedone(1); -+ DSSDBG("done waiting\n"); -+ -+ enable_clocks(0); -+ dsi_enable_pll_clock(0); -+} -+ -+static int dsi_set_update_mode(struct omap_display *display, -+ enum omap_dss_update_mode mode) -+{ -+ if (mode == dsi.update_mode) -+ return 0; -+ -+ if (dsi.update_mode == OMAP_DSS_UPDATE_AUTO) -+ dsi_stop_auto_update(); -+ else if (dsi.update_mode == OMAP_DSS_UPDATE_MANUAL) -+ dsi_wait_for_framedone(0); -+ -+ dsi.update_mode = mode; -+ -+ if (dsi.update_mode == OMAP_DSS_UPDATE_AUTO) -+ dsi_start_auto_update(display); -+ -+ return 0; -+} -+ -+/* Display funcs */ -+ -+static int dsi_display_enable(struct omap_display *display) -+{ -+ int r = 0; -+ struct dsi_clock_info cinfo; -+ u32 low, high; -+ -+ DSSDBG("dsi_display_enable\n"); -+ -+ mutex_lock(&dsi.lock); -+ -+ if (display->state != OMAP_DSS_DISPLAY_DISABLED) { -+ DSSERR("display already enabled\n"); -+ r = -EINVAL; -+ goto err0; -+ } -+ -+ enable_clocks(1); -+ dsi_enable_pll_clock(1); -+ -+ r = omap_dispc_register_isr(framedone_callback, NULL, -+ DISPC_IRQ_FRAMEDONE); -+ if (r) { -+ DSSERR("can't get FRAMEDONE irq\n"); -+ goto err1; -+ } -+ -+ dispc_set_lcd_display_type(OMAP_DSS_LCD_DISPLAY_TFT); -+ -+ dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_DSI); -+ dispc_enable_fifohandcheck(1); -+ -+ dispc_set_burst_size(OMAP_DSS_GFX, OMAP_DSS_BURST_16x32); -+ dispc_set_burst_size(OMAP_DSS_VIDEO1, OMAP_DSS_BURST_16x32); -+ dispc_set_burst_size(OMAP_DSS_VIDEO2, OMAP_DSS_BURST_16x32); -+ -+ high = dispc_get_plane_fifo_size(OMAP_DSS_GFX) - (16*32/8); -+ low = 0; -+ dispc_setup_plane_fifo(OMAP_DSS_GFX, low, high); -+ -+ high = dispc_get_plane_fifo_size(OMAP_DSS_VIDEO1) - (16*32/8); -+ low = 0; -+ dispc_setup_plane_fifo(OMAP_DSS_VIDEO1, low, high); -+ -+ high = dispc_get_plane_fifo_size(OMAP_DSS_VIDEO2) - (16*32/8); -+ low = 0; -+ dispc_setup_plane_fifo(OMAP_DSS_VIDEO2, low, high); -+ -+ dispc_set_tft_data_lines(display->ctrl->pixel_size); -+ -+ { -+ struct omap_video_timings timings = { -+ .hsw = 1, -+ .hfp = 1, -+ .hbp = 1, -+ .vsw = 1, -+ .vfp = 0, -+ .vbp = 0, -+ }; -+ -+ dispc_set_lcd_timings(&timings); -+ } -+ -+ _dsi_print_reset_status(); -+ -+ r = dsi_pll_init(1, 0); -+ if (r) -+ goto err2; -+ -+ r = dsi_pll_calc_ddrfreq(display->hw_config.u.dsi.ddr_clk_hz, &cinfo); -+ if (r) -+ goto err3; -+ -+ r = dsi_pll_program(&cinfo); -+ if (r) -+ goto err3; -+ -+ DSSDBG("PLL OK\n"); -+ -+ r = dsi_complexio_init(display); -+ if (r) -+ goto err3; -+ -+ _dsi_print_reset_status(); -+ -+ dsi_proto_timings(); -+ dsi_set_lp_clk_divisor(); -+ -+ if (1) -+ _dsi_print_reset_status(); -+ -+ r = dsi_proto_config(display); -+ if (r) -+ goto err4; -+ -+ /* enable interface */ -+ dsi_vc_enable(0, 1); -+ dsi_vc_enable(1, 1); -+ dsi_if_enable(1); -+ dsi_force_tx_stop_mode_io(); -+ -+ -+ if (display->ctrl && display->ctrl->enable) { -+ r = display->ctrl->enable(display); -+ if (r) -+ goto err5; -+ } -+ -+ if (display->panel && display->panel->enable) { -+ r = display->panel->enable(display); -+ if (r) -+ goto err6; -+ } -+ -+ if (dsi.use_te) { -+ r = display->ctrl->enable_te(display, 1); -+ if (r) -+ goto err7; -+ } -+ -+ /* enable high-speed after initial config */ -+ dsi_vc_enable_hs(0, 1); -+ -+ display->state = OMAP_DSS_DISPLAY_ACTIVE; -+ -+ dsi_set_update_mode(display, dsi.user_update_mode); -+ -+ enable_clocks(0); -+ dsi_enable_pll_clock(0); -+ mutex_unlock(&dsi.lock); -+ -+ return 0; -+err7: -+ if (display->panel && display->panel->disable) -+ display->panel->disable(display); -+err6: -+ if (display->ctrl && display->ctrl->disable) -+ display->ctrl->disable(display); -+err5: -+ dsi_if_enable(0); -+err4: -+ dsi_complexio_uninit(); -+err3: -+ dsi_pll_uninit(); -+err2: -+ omap_dispc_unregister_isr(framedone_callback); -+err1: -+ enable_clocks(0); -+ dsi_enable_pll_clock(0); -+err0: -+ mutex_unlock(&dsi.lock); -+ DSSDBG("dsi_display_enable FAILED\n"); -+ return r; -+} -+ -+static void dsi_display_disable(struct omap_display *display) -+{ -+ DSSDBG("dsi_display_disable\n"); -+ -+ mutex_lock(&dsi.lock); -+ -+ if (display->state == OMAP_DSS_DISPLAY_DISABLED) -+ goto end; -+ -+ enable_clocks(1); -+ dsi_enable_pll_clock(1); -+ -+ dsi_set_update_mode(display, OMAP_DSS_UPDATE_DISABLED); -+ -+ display->state = OMAP_DSS_DISPLAY_DISABLED; -+ -+ omap_dispc_unregister_isr(framedone_callback); -+ -+ if (display->panel && display->panel->disable) -+ display->panel->disable(display); -+ if (display->ctrl && display->ctrl->disable) -+ display->ctrl->disable(display); -+ -+ dsi_complexio_uninit(); -+ dsi_pll_uninit(); -+ -+ enable_clocks(0); -+ dsi_enable_pll_clock(0); -+end: -+ mutex_unlock(&dsi.lock); -+} -+ -+static int dsi_display_suspend(struct omap_display *display) -+{ -+ if (display->state != OMAP_DSS_DISPLAY_ACTIVE) -+ return -EINVAL; -+ -+ if (display->panel->suspend) -+ display->panel->suspend(display); -+ -+ if (display->ctrl->suspend) -+ display->ctrl->suspend(display); -+ -+ display->state = OMAP_DSS_DISPLAY_SUSPENDED; -+ -+ return 0; -+} -+ -+static int dsi_display_resume(struct omap_display *display) -+{ -+ if (display->state != OMAP_DSS_DISPLAY_SUSPENDED) -+ return -EINVAL; -+ -+ if (display->panel->resume) -+ display->panel->resume(display); -+ -+ if (display->ctrl->resume) -+ display->ctrl->resume(display); -+ -+ display->state = OMAP_DSS_DISPLAY_ACTIVE; -+ -+ return 0; -+} -+ -+static int dsi_display_update(struct omap_display *display, -+ int x, int y, int w, int h) -+{ -+ unsigned long flags; -+ int r = 0; -+ -+ DSSDBG("dsi_display_update(%d,%d %dx%d)\n", x, y, w, h); -+ -+ if (w == 0 || h == 0) -+ return 0; -+ -+ mutex_lock(&dsi.lock); -+ -+ if (dsi.update_mode != OMAP_DSS_UPDATE_MANUAL) -+ goto end; /* XXX return error? */ -+ -+ spin_lock_irqsave(&dsi.update_lock, flags); -+ -+ if (dsi.update_ongoing) { -+ spin_unlock_irqrestore(&dsi.update_lock, flags); -+ DSSERR("DSI is busy\n"); -+ r = -EBUSY; -+ goto end; -+ } -+ -+ perf_mark_setup(); -+ -+ dsi.update_ongoing = 1; -+ -+ if (dsi.update_syncers > 0) -+ DSSERR("someone waiting for sync, and no update ongoing\n"); -+ -+ spin_unlock_irqrestore(&dsi.update_lock, flags); -+ -+ if (display->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { -+ dsi_setup_update_dispc(display, x, y, w, h); -+ dsi_update_screen_dispc(display); -+ } else { -+ r = dsi_update_screen_l4(display, x, y, w, h); -+ if (r) -+ goto end; -+ -+ spin_lock_irqsave(&dsi.update_lock, flags); -+ dsi.update_ongoing = 0; -+ while (dsi.update_syncers > 0) { -+ complete(&dsi.update_completion); -+ --dsi.update_syncers; -+ } -+ spin_unlock_irqrestore(&dsi.update_lock, flags); -+ } -+ -+end: -+ mutex_unlock(&dsi.lock); -+ return r; -+} -+ -+static int dsi_display_sync(struct omap_display *display) -+{ -+ int r = 0; -+ -+ DSSDBG("dsi_display_sync\n"); -+ -+ mutex_lock(&dsi.lock); -+ -+ if (dsi.update_mode != OMAP_DSS_UPDATE_MANUAL) -+ goto end; -+ -+ r = dsi_wait_for_framedone(0); -+ -+end: -+ mutex_unlock(&dsi.lock); -+ return r; -+} -+ -+static int dsi_display_set_update_mode(struct omap_display *display, -+ enum omap_dss_update_mode mode) -+{ -+ int r; -+ -+ DSSDBG("dsi_display_set_update_mode\n"); -+ -+ mutex_lock(&dsi.lock); -+ -+ r = dsi_set_update_mode(display, mode); -+ dsi.user_update_mode = mode; -+ -+ mutex_unlock(&dsi.lock); -+ -+ return r; -+} -+ -+static enum omap_dss_update_mode dsi_display_get_update_mode( -+ struct omap_display *display) -+{ -+ return dsi.user_update_mode; -+} -+ -+static int dsi_display_enable_te(struct omap_display *display, int enable) -+{ -+ DSSDBG("dsi_display_enable_te\n"); -+ -+ mutex_lock(&dsi.lock); -+ -+ enable_clocks(1); -+ dsi_enable_pll_clock(1); -+ -+ dsi_set_update_mode(display, OMAP_DSS_UPDATE_DISABLED); -+ -+ dsi.use_te = enable; -+ display->ctrl->enable_te(display, enable); -+ if (enable) { -+ /* disable LP_RX_TO, so that we can receive TE. -+ * Time to wait for TE is longer than the timer allows */ -+ REG_FLD_MOD(DSI_TIMING2, 0, 15, 15); /* LP_RX_TO */ -+ } else { -+ REG_FLD_MOD(DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */ -+ } -+ -+ /* restore the old update mode */ -+ dsi_set_update_mode(display, dsi.user_update_mode); -+ -+ enable_clocks(0); -+ dsi_enable_pll_clock(0); -+ -+ mutex_unlock(&dsi.lock); -+ -+ return 0; -+} -+ -+static int dsi_display_get_te(struct omap_display *display) -+{ -+ return dsi.use_te; -+} -+ -+static int dsi_display_run_test(struct omap_display *display, int test_num) -+{ -+ int r = 0; -+ -+ DSSDBG("dsi_display_run_test %d\n", test_num); -+ -+ mutex_lock(&dsi.lock); -+ -+ enable_clocks(1); -+ dsi_enable_pll_clock(1); -+ -+ dsi_set_update_mode(display, OMAP_DSS_UPDATE_DISABLED); -+ -+ /* run test first in low speed mode */ -+ dsi_vc_enable_hs(0, 0); -+ -+ if (display->ctrl->run_test) { -+ r = display->ctrl->run_test(display, test_num); -+ if (r) -+ goto fail; -+ } -+ -+ if (display->panel->run_test) { -+ r = display->panel->run_test(display, test_num); -+ if (r) -+ goto fail; -+ } -+ -+ /* then in high speed */ -+ dsi_vc_enable_hs(0, 1); -+ -+ if (display->ctrl->run_test) { -+ r = display->ctrl->run_test(display, test_num); -+ if (r) -+ goto fail; -+ } -+ -+ if (display->panel->run_test) -+ r = display->panel->run_test(display, test_num); -+ -+fail: -+ dsi_vc_enable_hs(0, 1); -+ -+ /* restore the old update mode */ -+ dsi_set_update_mode(display, dsi.user_update_mode); -+ -+ enable_clocks(0); -+ dsi_enable_pll_clock(0); -+ -+ mutex_unlock(&dsi.lock); -+ -+ return r; -+} -+ -+void dsi_init_display(struct omap_display *display) -+{ -+ DSSDBG("DSI init\n"); -+ -+ display->enable = dsi_display_enable; -+ display->disable = dsi_display_disable; -+ display->suspend = dsi_display_suspend; -+ display->resume = dsi_display_resume; -+ display->update = dsi_display_update; -+ display->sync = dsi_display_sync; -+ display->set_update_mode = dsi_display_set_update_mode; -+ display->get_update_mode = dsi_display_get_update_mode; -+ display->enable_te = dsi_display_enable_te; -+ display->get_te = dsi_display_get_te; -+ display->run_test = dsi_display_run_test; -+ -+ display->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE; -+} -+ -+int dsi_init(void) -+{ -+ u32 rev; -+ -+ init_completion(&dsi.bta_completion); -+ INIT_DELAYED_WORK(&dsi.framedone_work, framedone_worker); -+ -+ init_completion(&dsi.update_completion); -+ spin_lock_init(&dsi.update_lock); -+ dsi.update_ongoing = 0; -+ dsi.update_syncers = 0; -+ -+ mutex_init(&dsi.lock); -+ -+ dsi.base = ioremap(DSI_BASE, DSI_SZ_REGS); -+ if (!dsi.base) { -+ DSSERR("can't ioremap DSI\n"); -+ return -ENOMEM; -+ } -+ -+ enable_clocks(1); -+ -+ /* Autoidle */ -+ REG_FLD_MOD(DSI_SYSCONFIG, 1, 0, 0); -+ -+ /* ENWAKEUP */ -+ REG_FLD_MOD(DSI_SYSCONFIG, 1, 2, 2); -+ -+ /* SIDLEMODE smart-idle */ -+ REG_FLD_MOD(DSI_SYSCONFIG, 2, 4, 3); -+ -+ _dsi_initialize_irq(); -+ -+ rev = dsi_read_reg(DSI_REVISION); -+ printk(KERN_INFO "OMAP DSI rev %d.%d\n", -+ FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); -+ -+ enable_clocks(0); -+ -+ return 0; -+} -+ -+void dsi_exit(void) -+{ -+ iounmap(dsi.base); -+ -+ DSSDBG("omap_dsi_exit\n"); -+} -+ -diff --git a/arch/arm/plat-omap/dss/dss.c b/arch/arm/plat-omap/dss/dss.c -new file mode 100644 -index 0000000..4a403c1 ---- /dev/null -+++ b/arch/arm/plat-omap/dss/dss.c -@@ -0,0 +1,774 @@ -+/* -+ * linux/arch/arm/plat-omap/dss/dss.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/>. -+ */ -+ -+#define DSS_SUBSYS_NAME "DSS" -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/io.h> -+#include <linux/clk.h> -+#include <linux/err.h> -+#include <linux/delay.h> -+#include <linux/interrupt.h> -+#include <linux/platform_device.h> -+ -+#include <mach/display.h> -+#include <mach/clock.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 *dss_ick; -+ struct clk *dss1_fck; -+ struct clk *dss2_fck; -+ struct clk *dss_54m_fck; -+ struct clk *dss_96m_fck; -+ -+ unsigned num_clks_enabled; -+ struct platform_device *pdev; -+ unsigned ctx_id; -+ u32 ctx[DSS_SZ_REGS / sizeof(u32)]; -+} dss; -+ -+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 int _omap_dss_wait_reset(void); -+ -+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 -+ -+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)]) -+ -+static void dss_save_context(void) -+{ -+ if (cpu_is_omap24xx()) -+ return; -+ -+ SR(SYSCONFIG); -+ SR(CONTROL); -+ SR(SDI_CONTROL); -+ SR(PLL_CONTROL); -+} -+ -+static void dss_restore_context(void) -+{ -+ RR(SYSCONFIG); -+ RR(CONTROL); -+ RR(SDI_CONTROL); -+ RR(PLL_CONTROL); -+} -+ -+#undef SR -+#undef RR -+ -+static unsigned dss_get_ctx_id(void) -+{ -+ struct omap_dss_platform_data *pdata = dss.pdev->dev.platform_data; -+ -+ if (!pdata->get_last_off_on_transaction_id) -+ return 0; -+ -+ return pdata->get_last_off_on_transaction_id(&dss.pdev->dev); -+} -+ -+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(); -+ -+ if (_omap_dss_wait_reset()) -+ DSSERR("DSS not coming out of reset after sleep\n"); -+ -+ dss_restore_context(); -+ dispc_restore_context(); -+#ifdef CONFIG_OMAP2_DSS_DSI -+ dsi_restore_context(); -+#endif -+ -+ dss_clk_disable_all_no_ctx(); -+} -+ -+void dss_sdi_init(int 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); -+ -+ /* 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 */ -+ while (dss_read_reg(DSS_SDI_STATUS) & (1 << 6)) -+ ; -+ -+ /* Clearing PLL_GO bit */ -+ REG_FLD_MOD(DSS_PLL_CONTROL, 0, 28, 28); -+ -+ /* Waiting for PLL to lock */ -+ while (!(dss_read_reg(DSS_SDI_STATUS) & (1 << 5))) -+ ; -+ -+ dispc_lcd_enable_signal(1); -+ -+ /* Waiting for SDI reset to complete */ -+ while (!(dss_read_reg(DSS_SDI_STATUS) & (1 << 5))) -+ ; -+} -+ -+ssize_t dss_print_clocks(char *buf, ssize_t size) -+{ -+ ssize_t l = 0; -+ int i; -+ struct clk *clocks[5] = { -+ dss.dss_ick, -+ dss.dss1_fck, -+ dss.dss2_fck, -+ dss.dss_54m_fck, -+ dss.dss_96m_fck -+ }; -+ -+ l += snprintf(buf + l, size - l, "- dss -\n"); -+ -+ l += snprintf(buf + l, size - l, "internal clk count\t%u\n", -+ dss.num_clks_enabled); -+ -+ for (i = 0; i < 5; i++) { -+ if (!clocks[i]) -+ continue; -+ l += snprintf(buf + l, size - l, "%-15s\t%lu\t%d\n", -+ clocks[i]->name, -+ clk_get_rate(clocks[i]), -+ clk_get_usecount(clocks[i])); -+ } -+ -+ return l; -+} -+ -+static int get_dss_clocks(void) -+{ -+ const struct { -+ struct clk **clock; -+ char *omap2_name; -+ char *omap3_name; -+ } clocks[5] = { -+ { &dss.dss_ick, "dss_ick", "dss_ick" }, /* L3 & L4 ick */ -+ { &dss.dss1_fck, "dss1_fck", "dss1_alwon_fck" }, -+ { &dss.dss2_fck, "dss2_fck", "dss2_alwon_fck" }, -+ { &dss.dss_54m_fck, "dss_54m_fck", "dss_tv_fck" }, -+ { &dss.dss_96m_fck, NULL, "dss_96m_fck" }, -+ }; -+ -+ int r = 0; -+ int i; -+ const int num_clocks = 5; -+ -+ for (i = 0; i < num_clocks; i++) -+ *clocks[i].clock = NULL; -+ -+ for (i = 0; i < num_clocks; i++) { -+ struct clk *clk; -+ const char *clk_name; -+ -+ clk_name = cpu_is_omap34xx() ? clocks[i].omap3_name -+ : clocks[i].omap2_name; -+ -+ if (!clk_name) -+ continue; -+ -+ clk = clk_get(NULL, clk_name); -+ -+ if (IS_ERR(clk)) { -+ DSSERR("can't get clock %s", clk_name); -+ r = PTR_ERR(clk); -+ goto err; -+ } -+ -+ DSSDBG("clk %s, rate %ld\n", -+ clk_name, clk_get_rate(clk)); -+ -+ *clocks[i].clock = clk; -+ } -+ -+ return 0; -+ -+err: -+ for (i = 0; i < num_clocks; i++) { -+ if (!IS_ERR(*clocks[i].clock)) -+ clk_put(*clocks[i].clock); -+ } -+ -+ return r; -+} -+ -+static void put_dss_clocks(void) -+{ -+ if (dss.dss_96m_fck) -+ clk_put(dss.dss_96m_fck); -+ clk_put(dss.dss_54m_fck); -+ clk_put(dss.dss1_fck); -+ clk_put(dss.dss2_fck); -+ clk_put(dss.dss_ick); -+} -+ -+unsigned long dss_clk_get_rate(enum dss_clock clk) -+{ -+ switch (clk) { -+ case DSS_CLK_ICK: -+ return clk_get_rate(dss.dss_ick); -+ case DSS_CLK_FCK1: -+ return clk_get_rate(dss.dss1_fck); -+ case DSS_CLK_FCK2: -+ return clk_get_rate(dss.dss2_fck); -+ case DSS_CLK_54M: -+ return clk_get_rate(dss.dss_54m_fck); -+ case DSS_CLK_96M: -+ return clk_get_rate(dss.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(dss.dss_ick); -+ if (clks & DSS_CLK_FCK1) -+ clk_enable(dss.dss1_fck); -+ if (clks & DSS_CLK_FCK2) -+ clk_enable(dss.dss2_fck); -+ if (clks & DSS_CLK_54M) -+ clk_enable(dss.dss_54m_fck); -+ if (clks & DSS_CLK_96M) -+ clk_enable(dss.dss_96m_fck); -+ -+ dss.num_clks_enabled += num_clks; -+} -+ -+void dss_clk_enable(enum dss_clock clks) -+{ -+ dss_clk_enable_no_ctx(clks); -+ -+ if (cpu_is_omap34xx()) { -+ int id = dss_get_ctx_id(); -+ -+ if (id != dss.ctx_id) { -+ DSSDBG("ctx id %u -> id %u\n", -+ dss.ctx_id, id); -+ restore_all_ctx(); -+ dss.ctx_id = id; -+ } -+ } -+} -+ -+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(dss.dss_ick); -+ if (clks & DSS_CLK_FCK1) -+ clk_disable(dss.dss1_fck); -+ if (clks & DSS_CLK_FCK2) -+ clk_disable(dss.dss2_fck); -+ if (clks & DSS_CLK_54M) -+ clk_disable(dss.dss_54m_fck); -+ if (clks & DSS_CLK_96M) -+ clk_disable(dss.dss_96m_fck); -+ -+ dss.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(dss.num_clks_enabled < num_clks); -+ -+ if (dss.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); -+} -+ -+void dss_select_clk_source(int dsi, int 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); -+} -+ -+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(int enable) -+{ -+ REG_FLD_MOD(DSS_CONTROL, enable, 5, 5); /* DAC Power-Down Control */ -+} -+ -+int dss_init(void) -+{ -+ 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; -+ } -+ -+ /* We need to wait here a bit, otherwise we sometimes start to get -+ * synclost errors. I believe we could wait for one framedone or -+ * perhaps vsync interrupt, but, because dispc is not initialized yet, -+ * we don't have access to the irq register. -+ */ -+ msleep(400); -+ -+ _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; -+ } -+ -+ 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; -+ -+fail1: -+ iounmap(dss.base); -+fail0: -+ return r; -+} -+ -+void dss_exit(void) -+{ -+ int c; -+ -+ free_irq(INT_24XX_DSS_IRQ, NULL); -+ -+ /* these should be removed at some point */ -+ c = clk_get_usecount(dss.dss_ick); -+ if (c > 0) { -+ DSSERR("warning: dss_ick usecount %d, disabling\n", c); -+ while (c-- > 0) -+ clk_disable(dss.dss_ick); -+ } -+ -+ c = clk_get_usecount(dss.dss1_fck); -+ if (c > 0) { -+ DSSERR("warning: dss1_fck usecount %d, disabling\n", c); -+ while (c-- > 0) -+ clk_disable(dss.dss1_fck); -+ } -+ -+ c = clk_get_usecount(dss.dss2_fck); -+ if (c > 0) { -+ DSSERR("warning: dss2_fck usecount %d, disabling\n", c); -+ while (c-- > 0) -+ clk_disable(dss.dss2_fck); -+ } -+ -+ c = clk_get_usecount(dss.dss_54m_fck); -+ if (c > 0) { -+ DSSERR("warning: dss_54m_fck usecount %d, disabling\n", c); -+ while (c-- > 0) -+ clk_disable(dss.dss_54m_fck); -+ } -+ -+ if (dss.dss_96m_fck) { -+ c = clk_get_usecount(dss.dss_96m_fck); -+ if (c > 0) { -+ DSSERR("warning: dss_96m_fck usecount %d, disabling\n", -+ c); -+ while (c-- > 0) -+ clk_disable(dss.dss_96m_fck); -+ } -+ } -+ -+ put_dss_clocks(); -+ -+ iounmap(dss.base); -+} -+ -+ -+ -+static int omap_dss_probe(struct platform_device *pdev) -+{ -+ struct omap_dss_platform_data *pdata = pdev->dev.platform_data; -+ -+ int r; -+ -+ dss.pdev = pdev; -+ -+ r = get_dss_clocks(); -+ if (r) -+ goto fail0; -+ -+ dss_clk_enable_all_no_ctx(); -+ -+ dss.ctx_id = dss_get_ctx_id(); -+ DSSDBG("initial ctx id %u\n", dss.ctx_id); -+ -+ r = dss_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(); -+ if (r) { -+ DSSERR("Failed to initialize venc\n"); -+ goto fail0; -+ } -+#endif -+ if (cpu_is_omap34xx()) { -+#ifdef CONFIG_OMAP2_DSS_SDI -+ r = sdi_init(); -+ if (r) { -+ DSSERR("Failed to initialize SDI\n"); -+ goto fail0; -+ } -+#endif -+#ifdef CONFIG_OMAP2_DSS_DSI -+ r = dsi_init(); -+ if (r) { -+ DSSERR("Failed to initialize DSI\n"); -+ goto fail0; -+ } -+#endif -+ } -+ -+ initialize_displays(pdata); -+ -+ r = initialize_sysfs(&pdev->dev); -+ if (r) -+ goto fail0; -+ -+ initialize_overlays(def_disp_name); -+ -+ dss_clk_disable_all(); -+ -+ return 0; -+ -+ /* XXX fail correctly */ -+fail0: -+ return r; -+} -+ -+static int omap_dss_remove(struct platform_device *pdev) -+{ -+ uninitialize_sysfs(&pdev->dev); -+ -+#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(); -+ -+ return 0; -+} -+ -+ -+static struct platform_driver omap_dss_driver = { -+ .probe = omap_dss_probe, -+ .remove = omap_dss_remove, -+ .driver = { -+ .name = "omap-dss", -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+static int __init omap_dss_init(void) -+{ -+ return platform_driver_register(&omap_dss_driver); -+} -+ -+static void __exit omap_dss_exit(void) -+{ -+ platform_driver_unregister(&omap_dss_driver); -+} -+ -+subsys_initcall(omap_dss_init); -+module_exit(omap_dss_exit); -+ -+ -+MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>"); -+MODULE_DESCRIPTION("OMAP2/3 Display Subsystem"); -+MODULE_LICENSE("GPL v2"); -+ -diff --git a/arch/arm/plat-omap/dss/dss.h b/arch/arm/plat-omap/dss/dss.h -new file mode 100644 -index 0000000..da628a7 ---- /dev/null -+++ b/arch/arm/plat-omap/dss/dss.h -@@ -0,0 +1,274 @@ -+/* -+ * linux/arch/arm/plat-omap/dss/dss.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 __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 "omap-dss " DSS_SUBSYS_NAME ": " format, \ -+ ## __VA_ARGS__) -+#else -+#define DSSDBG(format, ...) \ -+ if (dss_debug) \ -+ printk(KERN_DEBUG "omap-dss: " format, ## __VA_ARGS__) -+#endif -+#else -+#define DSSDBG(format, ...) -+#endif -+ -+#ifdef DSS_SUBSYS_NAME -+#define DSSERR(format, ...) \ -+ printk(KERN_ERR "omap-dss " DSS_SUBSYS_NAME " error: " format, \ -+ ## __VA_ARGS__) -+#else -+#define DSSERR(format, ...) \ -+ printk(KERN_ERR "omap-dss error: " format, ## __VA_ARGS__) -+#endif -+ -+#ifdef DSS_SUBSYS_NAME -+#define DSSINFO(format, ...) \ -+ printk(KERN_INFO "omap-dss " DSS_SUBSYS_NAME ": " format, \ -+ ## __VA_ARGS__) -+#else -+#define DSSINFO(format, ...) \ -+ printk(KERN_INFO "omap-dss: " format, ## __VA_ARGS__) -+#endif -+ -+#ifdef DSS_SUBSYS_NAME -+#define DSSWARN(format, ...) \ -+ printk(KERN_WARNING "omap-dss " DSS_SUBSYS_NAME ": " format, \ -+ ## __VA_ARGS__) -+#else -+#define DSSWARN(format, ...) \ -+ printk(KERN_WARNING "omap-dss: " 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 dispc_clock_info { -+ /* rates that we get with dividers below */ -+ unsigned long fck; -+ unsigned long lck; -+ unsigned long pck; -+ -+ /* dividers */ -+ int fck_div; -+ int lck_div; -+ int pck_div; -+}; -+ -+struct dsi_clock_info { -+ /* rates that we get with dividers below */ -+ unsigned long fint; -+ unsigned long dsiphy; -+ unsigned long clkin; /* input clk for DSI PLL */ -+ unsigned long dispc_fck; /* output clk, DSI1_PLL_FCLK */ -+ unsigned long dsi_fck; /* output clk, DSI2_PLL_FCLK */ -+ unsigned long lck; -+ unsigned long pck; -+ -+ /* dividers */ -+ int regn; -+ int regm; -+ int regm3; -+ int regm4; -+ -+ int lck_div; -+ int pck_div; -+ -+ int highfreq; -+ int use_dss2_fck; -+}; -+ -+int initialize_sysfs(struct device *dev); -+void uninitialize_sysfs(struct device *dev); -+void initialize_displays(struct omap_dss_platform_data *pdata); -+void initialize_overlays(const char *def_disp_name); -+ -+/* DSS */ -+int dss_init(void); -+void dss_exit(void); -+ -+void dss_clk_enable(enum dss_clock clks); -+void dss_clk_disable(enum dss_clock clks); -+ -+void dss_sdi_init(int datapairs); -+void dss_select_clk_source(int dsi, int 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(int enable); -+unsigned long dss_clk_get_rate(enum dss_clock clk); -+ssize_t dss_print_clocks(char *buf, ssize_t size); -+ -+/* SDI */ -+int sdi_init(void); -+void sdi_exit(void); -+void sdi_init_display(struct omap_display *display); -+ -+ -+/* DSI */ -+int dsi_init(void); -+void dsi_exit(void); -+ -+void dsi_save_context(void); -+void dsi_restore_context(void); -+ -+void dsi_init_display(struct omap_display *display); -+void dsi_irq_handler(void); -+unsigned long dsi_get_dsi1_pll_rate(void); -+unsigned long dsi_get_dsi2_pll_rate(void); -+int dsi_pll_calc_pck(int is_tft, unsigned long req_pck, -+ struct dsi_clock_info *cinfo); -+int dsi_pll_program(struct dsi_clock_info *cinfo); -+int dsi_pll_init(int enable_hsclk, int enable_hsdiv); -+void dsi_pll_uninit(void); -+ssize_t dsi_print_clocks(char *buf, ssize_t size); -+ -+/* DPI */ -+int dpi_init(void); -+void dpi_exit(void); -+void dpi_init_display(struct omap_display *display); -+ -+/* DISPC */ -+int dispc_init(void); -+void dispc_exit(void); -+void dispc_irq_handler(void); -+void dispc_fake_vsync_irq(void); -+ -+void dispc_save_context(void); -+void dispc_restore_context(void); -+ -+void dispc_lcd_enable_signal_polarity(int act_high); -+void dispc_lcd_enable_signal(int enable); -+void dispc_pck_free_enable(int enable); -+void dispc_enable_fifohandcheck(int enable); -+ -+void dispc_set_lcd_size(int width, int height); -+void dispc_set_digit_size(int width, int 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_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, int x, int y); -+void dispc_set_plane_size(enum omap_plane plane, int width, int height); -+void dispc_set_row_inc(enum omap_plane plane, int inc); -+ -+int dispc_setup_plane(enum omap_plane plane, enum omap_channel channel_out, -+ u32 paddr, int screen_width, -+ int pos_x, int pos_y, -+ int width, int height, -+ int out_width, int out_height, -+ enum omap_color_mode color_mode, -+ int ilace); -+ -+void dispc_go(enum omap_channel channel); -+void dispc_enable_lcd_out(int enable); -+void dispc_enable_digit_out(int enable); -+int dispc_enable_plane(enum omap_plane plane, int enable); -+ -+void dispc_set_parallel_interface_mode(enum omap_parallel_interface_mode mode); -+void dispc_set_tft_data_lines(int 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); -+void dispc_set_trans_key(enum omap_channel ch, -+ enum omap_dss_color_key_type type, -+ u32 trans_key); -+void dispc_enable_trans_key(enum omap_channel ch, int enable); -+ -+void dispc_set_lcd_timings(struct omap_video_timings *timings); -+unsigned long dispc_fclk_rate(void); -+unsigned long dispc_pclk_rate(void); -+void dispc_set_pol_freq(struct omap_panel *panel); -+void find_lck_pck_divs(int is_tft, unsigned long req_pck, unsigned long fck, -+ int *lck_div, int *pck_div); -+int dispc_calc_clock_div(int is_tft, unsigned long req_pck, -+ struct dispc_clock_info *cinfo); -+int dispc_set_clock_div(struct dispc_clock_info *cinfo); -+void dispc_set_lcd_divisor(int lck_div, int pck_div); -+ -+void dispc_setup_partial_planes(struct omap_display *display, -+ int *x, int *y, int *w, int *h); -+void dispc_draw_partial_planes(struct omap_display *display); -+ -+ -+ssize_t dispc_print_clocks(char *buf, ssize_t size); -+ -+/* VENC */ -+int venc_init(void); -+void venc_exit(void); -+void venc_init_display(struct omap_display *display); -+ -+/* RFBI */ -+int rfbi_init(void); -+void rfbi_exit(void); -+ -+int rfbi_configure(int rfbi_module, int bpp, int lines); -+void rfbi_enable_rfbi(int enable); -+void rfbi_transfer_area(int width, int 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); -+void rfbi_init_display(struct omap_display *display); -+ -+#endif -diff --git a/arch/arm/plat-omap/dss/rfbi.c b/arch/arm/plat-omap/dss/rfbi.c -new file mode 100644 -index 0000000..b4b65e6 ---- /dev/null -+++ b/arch/arm/plat-omap/dss/rfbi.c -@@ -0,0 +1,1262 @@ -+/* -+ * linux/arch/arm/plat-omap/dss/rfbi.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/>. -+ */ -+ -+#define DSS_SUBSYS_NAME "RFBI" -+ -+#include <linux/kernel.h> -+#include <linux/dma-mapping.h> -+#include <linux/vmalloc.h> -+#include <linux/clk.h> -+#include <linux/io.h> -+#include <linux/delay.h> -+#include <linux/kfifo.h> -+#include <linux/ktime.h> -+#include <linux/hrtimer.h> -+ -+#include <mach/board.h> -+#include <mach/display.h> -+#include "dss.h" -+ -+/*#define MEASURE_PERF*/ -+ -+#define RFBI_BASE 0x48050800 -+ -+struct rfbi_reg { u16 idx; }; -+ -+#define RFBI_REG(idx) ((const struct rfbi_reg) { idx }) -+ -+#define RFBI_REVISION RFBI_REG(0x0000) -+#define RFBI_SYSCONFIG RFBI_REG(0x0010) -+#define RFBI_SYSSTATUS RFBI_REG(0x0014) -+#define RFBI_CONTROL RFBI_REG(0x0040) -+#define RFBI_PIXEL_CNT RFBI_REG(0x0044) -+#define RFBI_LINE_NUMBER RFBI_REG(0x0048) -+#define RFBI_CMD RFBI_REG(0x004c) -+#define RFBI_PARAM RFBI_REG(0x0050) -+#define RFBI_DATA RFBI_REG(0x0054) -+#define RFBI_READ RFBI_REG(0x0058) -+#define RFBI_STATUS RFBI_REG(0x005c) -+ -+#define RFBI_CONFIG(n) RFBI_REG(0x0060 + (n)*0x18) -+#define RFBI_ONOFF_TIME(n) RFBI_REG(0x0064 + (n)*0x18) -+#define RFBI_CYCLE_TIME(n) RFBI_REG(0x0068 + (n)*0x18) -+#define RFBI_DATA_CYCLE1(n) RFBI_REG(0x006c + (n)*0x18) -+#define RFBI_DATA_CYCLE2(n) RFBI_REG(0x0070 + (n)*0x18) -+#define RFBI_DATA_CYCLE3(n) RFBI_REG(0x0074 + (n)*0x18) -+ -+#define RFBI_VSYNC_WIDTH RFBI_REG(0x0090) -+#define RFBI_HSYNC_WIDTH RFBI_REG(0x0094) -+ -+#define RFBI_CMD_FIFO_LEN_BYTES (16 * sizeof(struct update_param)) -+ -+#define REG_FLD_MOD(idx, val, start, end) \ -+ rfbi_write_reg(idx, FLD_MOD(rfbi_read_reg(idx), val, start, end)) -+ -+/* To work around an RFBI transfer rate limitation */ -+#define OMAP_RFBI_RATE_LIMIT 1 -+ -+enum omap_rfbi_cycleformat { -+ OMAP_DSS_RFBI_CYCLEFORMAT_1_1 = 0, -+ OMAP_DSS_RFBI_CYCLEFORMAT_2_1 = 1, -+ OMAP_DSS_RFBI_CYCLEFORMAT_3_1 = 2, -+ OMAP_DSS_RFBI_CYCLEFORMAT_3_2 = 3, -+}; -+ -+enum omap_rfbi_datatype { -+ OMAP_DSS_RFBI_DATATYPE_12 = 0, -+ OMAP_DSS_RFBI_DATATYPE_16 = 1, -+ OMAP_DSS_RFBI_DATATYPE_18 = 2, -+ OMAP_DSS_RFBI_DATATYPE_24 = 3, -+}; -+ -+enum omap_rfbi_parallelmode { -+ OMAP_DSS_RFBI_PARALLELMODE_8 = 0, -+ OMAP_DSS_RFBI_PARALLELMODE_9 = 1, -+ OMAP_DSS_RFBI_PARALLELMODE_12 = 2, -+ OMAP_DSS_RFBI_PARALLELMODE_16 = 3, -+}; -+ -+enum update_cmd { -+ RFBI_CMD_UPDATE = 0, -+ RFBI_CMD_SYNC = 1, -+}; -+ -+static int rfbi_convert_timings(struct rfbi_timings *t); -+static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div); -+static void process_cmd_fifo(void); -+ -+static struct { -+ void __iomem *base; -+ -+ unsigned long l4_khz; -+ -+ enum omap_rfbi_datatype datatype; -+ enum omap_rfbi_parallelmode parallelmode; -+ -+ enum omap_rfbi_te_mode te_mode; -+ int te_enabled; -+ -+ void (*framedone_callback)(void *data); -+ void *framedone_callback_data; -+ -+ struct omap_display *display[2]; -+ -+ struct kfifo *cmd_fifo; -+ spinlock_t cmd_lock; -+ struct completion cmd_done; -+ atomic_t cmd_fifo_full; -+ atomic_t cmd_pending; -+#ifdef MEASURE_PERF -+ unsigned perf_bytes; -+ ktime_t perf_setup_time; -+ ktime_t perf_start_time; -+#endif -+} rfbi; -+ -+struct update_region { -+ u16 x; -+ u16 y; -+ u16 w; -+ u16 h; -+}; -+ -+struct update_param { -+ u8 rfbi_module; -+ u8 cmd; -+ -+ union { -+ struct update_region r; -+ struct completion *sync; -+ } par; -+}; -+ -+static inline void rfbi_write_reg(const struct rfbi_reg idx, u32 val) -+{ -+ __raw_writel(val, rfbi.base + idx.idx); -+} -+ -+static inline u32 rfbi_read_reg(const struct rfbi_reg idx) -+{ -+ return __raw_readl(rfbi.base + idx.idx); -+} -+ -+static void rfbi_enable_clocks(int enable) -+{ -+ if (enable) -+ dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); -+ else -+ dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); -+} -+ -+void omap_rfbi_write_command(const void *buf, u32 len) -+{ -+ rfbi_enable_clocks(1); -+ switch (rfbi.parallelmode) { -+ case OMAP_DSS_RFBI_PARALLELMODE_8: -+ { -+ const u8 *b = buf; -+ for (; len; len--) -+ rfbi_write_reg(RFBI_CMD, *b++); -+ break; -+ } -+ -+ case OMAP_DSS_RFBI_PARALLELMODE_16: -+ { -+ const u16 *w = buf; -+ BUG_ON(len & 1); -+ for (; len; len -= 2) -+ rfbi_write_reg(RFBI_CMD, *w++); -+ break; -+ } -+ -+ case OMAP_DSS_RFBI_PARALLELMODE_9: -+ case OMAP_DSS_RFBI_PARALLELMODE_12: -+ default: -+ BUG(); -+ } -+ rfbi_enable_clocks(0); -+} -+EXPORT_SYMBOL(omap_rfbi_write_command); -+ -+void omap_rfbi_read_data(void *buf, u32 len) -+{ -+ rfbi_enable_clocks(1); -+ switch (rfbi.parallelmode) { -+ case OMAP_DSS_RFBI_PARALLELMODE_8: -+ { -+ u8 *b = buf; -+ for (; len; len--) { -+ rfbi_write_reg(RFBI_READ, 0); -+ *b++ = rfbi_read_reg(RFBI_READ); -+ } -+ break; -+ } -+ -+ case OMAP_DSS_RFBI_PARALLELMODE_16: -+ { -+ u16 *w = buf; -+ BUG_ON(len & ~1); -+ for (; len; len -= 2) { -+ rfbi_write_reg(RFBI_READ, 0); -+ *w++ = rfbi_read_reg(RFBI_READ); -+ } -+ break; -+ } -+ -+ case OMAP_DSS_RFBI_PARALLELMODE_9: -+ case OMAP_DSS_RFBI_PARALLELMODE_12: -+ default: -+ BUG(); -+ } -+ rfbi_enable_clocks(0); -+} -+EXPORT_SYMBOL(omap_rfbi_read_data); -+ -+void omap_rfbi_write_data(const void *buf, u32 len) -+{ -+ rfbi_enable_clocks(1); -+ switch (rfbi.parallelmode) { -+ case OMAP_DSS_RFBI_PARALLELMODE_8: -+ { -+ const u8 *b = buf; -+ for (; len; len--) -+ rfbi_write_reg(RFBI_PARAM, *b++); -+ break; -+ } -+ -+ case OMAP_DSS_RFBI_PARALLELMODE_16: -+ { -+ const u16 *w = buf; -+ BUG_ON(len & 1); -+ for (; len; len -= 2) -+ rfbi_write_reg(RFBI_PARAM, *w++); -+ break; -+ } -+ -+ case OMAP_DSS_RFBI_PARALLELMODE_9: -+ case OMAP_DSS_RFBI_PARALLELMODE_12: -+ default: -+ BUG(); -+ -+ } -+ rfbi_enable_clocks(0); -+} -+EXPORT_SYMBOL(omap_rfbi_write_data); -+ -+void omap_rfbi_write_pixels(const void *buf, int scr_width, int x, int y, -+ int w, int h) -+{ -+ int start_offset = scr_width * y + x; -+ int horiz_offset = scr_width - w; -+ int i; -+ -+ rfbi_enable_clocks(1); -+ -+ if (rfbi.datatype == OMAP_DSS_RFBI_DATATYPE_16 && -+ rfbi.parallelmode == OMAP_DSS_RFBI_PARALLELMODE_8) { -+ const u16 *pd = buf; -+ pd += start_offset; -+ -+ for (; h; --h) { -+ for (i = 0; i < w; ++i) { -+ const u8 *b = (const u8 *)pd; -+ rfbi_write_reg(RFBI_PARAM, *(b+1)); -+ rfbi_write_reg(RFBI_PARAM, *(b+0)); -+ ++pd; -+ } -+ pd += horiz_offset; -+ } -+ } else if (rfbi.datatype == OMAP_DSS_RFBI_DATATYPE_24 && -+ rfbi.parallelmode == OMAP_DSS_RFBI_PARALLELMODE_8) { -+ const u32 *pd = buf; -+ pd += start_offset; -+ -+ for (; h; --h) { -+ for (i = 0; i < w; ++i) { -+ const u8 *b = (const u8 *)pd; -+ rfbi_write_reg(RFBI_PARAM, *(b+2)); -+ rfbi_write_reg(RFBI_PARAM, *(b+1)); -+ rfbi_write_reg(RFBI_PARAM, *(b+0)); -+ ++pd; -+ } -+ pd += horiz_offset; -+ } -+ } else if (rfbi.datatype == OMAP_DSS_RFBI_DATATYPE_16 && -+ rfbi.parallelmode == OMAP_DSS_RFBI_PARALLELMODE_16) { -+ const u16 *pd = buf; -+ pd += start_offset; -+ -+ for (; h; --h) { -+ for (i = 0; i < w; ++i) { -+ rfbi_write_reg(RFBI_PARAM, *pd); -+ ++pd; -+ } -+ pd += horiz_offset; -+ } -+ } else { -+ BUG(); -+ } -+ -+ rfbi_enable_clocks(0); -+} -+EXPORT_SYMBOL(omap_rfbi_write_pixels); -+ -+#ifdef MEASURE_PERF -+static void perf_mark_setup(void) -+{ -+ rfbi.perf_setup_time = ktime_get(); -+} -+ -+static void perf_mark_start(void) -+{ -+ rfbi.perf_start_time = ktime_get(); -+} -+ -+static void perf_show(const char *name) -+{ -+ ktime_t t, setup_time, trans_time; -+ u32 total_bytes; -+ u32 setup_us, trans_us, total_us; -+ -+ t = ktime_get(); -+ -+ setup_time = ktime_sub(rfbi.perf_start_time, rfbi.perf_setup_time); -+ setup_us = (u32)ktime_to_us(setup_time); -+ if (setup_us == 0) -+ setup_us = 1; -+ -+ trans_time = ktime_sub(t, rfbi.perf_start_time); -+ trans_us = (u32)ktime_to_us(trans_time); -+ if (trans_us == 0) -+ trans_us = 1; -+ -+ total_us = setup_us + trans_us; -+ -+ total_bytes = rfbi.perf_bytes; -+ -+ DSSINFO("%s update %u us + %u us = %u us (%uHz), %u bytes, " -+ "%u kbytes/sec\n", -+ name, -+ setup_us, -+ trans_us, -+ total_us, -+ 1000*1000 / total_us, -+ total_bytes, -+ total_bytes * 1000 / total_us); -+} -+#else -+#define perf_mark_setup() -+#define perf_mark_start() -+#define perf_show(x) -+#endif -+ -+void rfbi_transfer_area(int width, int height, -+ void (callback)(void *data), void *data) -+{ -+ u32 l; -+ -+ /*BUG_ON(callback == 0);*/ -+ BUG_ON(rfbi.framedone_callback != NULL); -+ -+ DSSDBG("rfbi_transfer_area %dx%d\n", width, height); -+ -+ dispc_set_lcd_size(width, height); -+ -+ dispc_enable_lcd_out(1); -+ -+ rfbi.framedone_callback = callback; -+ rfbi.framedone_callback_data = data; -+ -+ rfbi_enable_clocks(1); -+ -+ rfbi_write_reg(RFBI_PIXEL_CNT, width * height); -+ -+ l = rfbi_read_reg(RFBI_CONTROL); -+ l = FLD_MOD(l, 1, 0, 0); /* enable */ -+ if (!rfbi.te_enabled) -+ l = FLD_MOD(l, 1, 4, 4); /* ITE */ -+ -+ perf_mark_start(); -+ -+ rfbi_write_reg(RFBI_CONTROL, l); -+} -+ -+static void framedone_callback(void *data, u32 mask) -+{ -+ void (*callback)(void *data); -+ -+ DSSDBG("FRAMEDONE\n"); -+ -+ perf_show("DISPC"); -+ -+ REG_FLD_MOD(RFBI_CONTROL, 0, 0, 0); -+ -+ rfbi_enable_clocks(0); -+ -+ callback = rfbi.framedone_callback; -+ rfbi.framedone_callback = NULL; -+ -+ /*callback(rfbi.framedone_callback_data);*/ -+ -+ atomic_set(&rfbi.cmd_pending, 0); -+ -+ process_cmd_fifo(); -+} -+ -+#if 1 /* VERBOSE */ -+static void rfbi_print_timings(void) -+{ -+ u32 l; -+ u32 time; -+ -+ l = rfbi_read_reg(RFBI_CONFIG(0)); -+ time = 1000000000 / rfbi.l4_khz; -+ if (l & (1 << 4)) -+ time *= 2; -+ -+ DSSDBG("Tick time %u ps\n", time); -+ l = rfbi_read_reg(RFBI_ONOFF_TIME(0)); -+ DSSDBG("CSONTIME %d, CSOFFTIME %d, WEONTIME %d, WEOFFTIME %d, " -+ "REONTIME %d, REOFFTIME %d\n", -+ l & 0x0f, (l >> 4) & 0x3f, (l >> 10) & 0x0f, (l >> 14) & 0x3f, -+ (l >> 20) & 0x0f, (l >> 24) & 0x3f); -+ -+ l = rfbi_read_reg(RFBI_CYCLE_TIME(0)); -+ DSSDBG("WECYCLETIME %d, RECYCLETIME %d, CSPULSEWIDTH %d, " -+ "ACCESSTIME %d\n", -+ (l & 0x3f), (l >> 6) & 0x3f, (l >> 12) & 0x3f, -+ (l >> 22) & 0x3f); -+} -+#else -+static void rfbi_print_timings(void) {} -+#endif -+ -+ -+ -+ -+static u32 extif_clk_period; -+ -+static inline unsigned long round_to_extif_ticks(unsigned long ps, int div) -+{ -+ int bus_tick = extif_clk_period * div; -+ return (ps + bus_tick - 1) / bus_tick * bus_tick; -+} -+ -+static int calc_reg_timing(struct rfbi_timings *t, int div) -+{ -+ t->clk_div = div; -+ -+ t->cs_on_time = round_to_extif_ticks(t->cs_on_time, div); -+ -+ t->we_on_time = round_to_extif_ticks(t->we_on_time, div); -+ t->we_off_time = round_to_extif_ticks(t->we_off_time, div); -+ t->we_cycle_time = round_to_extif_ticks(t->we_cycle_time, div); -+ -+ t->re_on_time = round_to_extif_ticks(t->re_on_time, div); -+ t->re_off_time = round_to_extif_ticks(t->re_off_time, div); -+ t->re_cycle_time = round_to_extif_ticks(t->re_cycle_time, div); -+ -+ t->access_time = round_to_extif_ticks(t->access_time, div); -+ t->cs_off_time = round_to_extif_ticks(t->cs_off_time, div); -+ t->cs_pulse_width = round_to_extif_ticks(t->cs_pulse_width, div); -+ -+ DSSDBG("[reg]cson %d csoff %d reon %d reoff %d\n", -+ t->cs_on_time, t->cs_off_time, t->re_on_time, t->re_off_time); -+ DSSDBG("[reg]weon %d weoff %d recyc %d wecyc %d\n", -+ t->we_on_time, t->we_off_time, t->re_cycle_time, -+ t->we_cycle_time); -+ DSSDBG("[reg]rdaccess %d cspulse %d\n", -+ t->access_time, t->cs_pulse_width); -+ -+ return rfbi_convert_timings(t); -+} -+ -+static int calc_extif_timings(struct rfbi_timings *t) -+{ -+ u32 max_clk_div; -+ int div; -+ -+ rfbi_get_clk_info(&extif_clk_period, &max_clk_div); -+ for (div = 1; div <= max_clk_div; div++) { -+ if (calc_reg_timing(t, div) == 0) -+ break; -+ } -+ -+ if (div <= max_clk_div) -+ return 0; -+ -+ DSSERR("can't setup timings\n"); -+ return -1; -+} -+ -+ -+void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t) -+{ -+ int r; -+ -+ if (!t->converted) { -+ r = calc_extif_timings(t); -+ if (r < 0) -+ DSSERR("Failed to calc timings\n"); -+ } -+ -+ BUG_ON(!t->converted); -+ -+ rfbi_enable_clocks(1); -+ rfbi_write_reg(RFBI_ONOFF_TIME(rfbi_module), t->tim[0]); -+ rfbi_write_reg(RFBI_CYCLE_TIME(rfbi_module), t->tim[1]); -+ -+ /* TIMEGRANULARITY */ -+ REG_FLD_MOD(RFBI_CONFIG(rfbi_module), -+ (t->tim[2] ? 1 : 0), 4, 4); -+ -+ rfbi_print_timings(); -+ rfbi_enable_clocks(0); -+} -+ -+static int ps_to_rfbi_ticks(int time, int div) -+{ -+ unsigned long tick_ps; -+ int ret; -+ -+ /* Calculate in picosecs to yield more exact results */ -+ tick_ps = 1000000000 / (rfbi.l4_khz) * div; -+ -+ ret = (time + tick_ps - 1) / tick_ps; -+ -+ return ret; -+} -+ -+#ifdef OMAP_RFBI_RATE_LIMIT -+unsigned long rfbi_get_max_tx_rate(void) -+{ -+ unsigned long l4_rate, dss1_rate; -+ int min_l4_ticks = 0; -+ int i; -+ -+ /* According to TI this can't be calculated so make the -+ * adjustments for a couple of known frequencies and warn for -+ * others. -+ */ -+ static const struct { -+ unsigned long l4_clk; /* HZ */ -+ unsigned long dss1_clk; /* HZ */ -+ unsigned long min_l4_ticks; -+ } ftab[] = { -+ { 55, 132, 7, }, /* 7.86 MPix/s */ -+ { 110, 110, 12, }, /* 9.16 MPix/s */ -+ { 110, 132, 10, }, /* 11 Mpix/s */ -+ { 120, 120, 10, }, /* 12 Mpix/s */ -+ { 133, 133, 10, }, /* 13.3 Mpix/s */ -+ }; -+ -+ l4_rate = rfbi.l4_khz / 1000; -+ dss1_rate = dss_clk_get_rate(DSS_CLK_FCK1) / 1000000; -+ -+ for (i = 0; i < ARRAY_SIZE(ftab); i++) { -+ /* Use a window instead of an exact match, to account -+ * for different DPLL multiplier / divider pairs. -+ */ -+ if (abs(ftab[i].l4_clk - l4_rate) < 3 && -+ abs(ftab[i].dss1_clk - dss1_rate) < 3) { -+ min_l4_ticks = ftab[i].min_l4_ticks; -+ break; -+ } -+ } -+ if (i == ARRAY_SIZE(ftab)) { -+ /* Can't be sure, return anyway the maximum not -+ * rate-limited. This might cause a problem only for the -+ * tearing synchronisation. -+ */ -+ DSSERR("can't determine maximum RFBI transfer rate\n"); -+ return rfbi.l4_khz * 1000; -+ } -+ return rfbi.l4_khz * 1000 / min_l4_ticks; -+} -+#else -+int rfbi_get_max_tx_rate(void) -+{ -+ return rfbi.l4_khz * 1000; -+} -+#endif -+ -+static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div) -+{ -+ *clk_period = 1000000000 / rfbi.l4_khz; -+ *max_clk_div = 2; -+} -+ -+static int rfbi_convert_timings(struct rfbi_timings *t) -+{ -+ u32 l; -+ int reon, reoff, weon, weoff, cson, csoff, cs_pulse; -+ int actim, recyc, wecyc; -+ int div = t->clk_div; -+ -+ if (div <= 0 || div > 2) -+ return -1; -+ -+ /* Make sure that after conversion it still holds that: -+ * weoff > weon, reoff > reon, recyc >= reoff, wecyc >= weoff, -+ * csoff > cson, csoff >= max(weoff, reoff), actim > reon -+ */ -+ weon = ps_to_rfbi_ticks(t->we_on_time, div); -+ weoff = ps_to_rfbi_ticks(t->we_off_time, div); -+ if (weoff <= weon) -+ weoff = weon + 1; -+ if (weon > 0x0f) -+ return -1; -+ if (weoff > 0x3f) -+ return -1; -+ -+ reon = ps_to_rfbi_ticks(t->re_on_time, div); -+ reoff = ps_to_rfbi_ticks(t->re_off_time, div); -+ if (reoff <= reon) -+ reoff = reon + 1; -+ if (reon > 0x0f) -+ return -1; -+ if (reoff > 0x3f) -+ return -1; -+ -+ cson = ps_to_rfbi_ticks(t->cs_on_time, div); -+ csoff = ps_to_rfbi_ticks(t->cs_off_time, div); -+ if (csoff <= cson) -+ csoff = cson + 1; -+ if (csoff < max(weoff, reoff)) -+ csoff = max(weoff, reoff); -+ if (cson > 0x0f) -+ return -1; -+ if (csoff > 0x3f) -+ return -1; -+ -+ l = cson; -+ l |= csoff << 4; -+ l |= weon << 10; -+ l |= weoff << 14; -+ l |= reon << 20; -+ l |= reoff << 24; -+ -+ t->tim[0] = l; -+ -+ actim = ps_to_rfbi_ticks(t->access_time, div); -+ if (actim <= reon) -+ actim = reon + 1; -+ if (actim > 0x3f) -+ return -1; -+ -+ wecyc = ps_to_rfbi_ticks(t->we_cycle_time, div); -+ if (wecyc < weoff) -+ wecyc = weoff; -+ if (wecyc > 0x3f) -+ return -1; -+ -+ recyc = ps_to_rfbi_ticks(t->re_cycle_time, div); -+ if (recyc < reoff) -+ recyc = reoff; -+ if (recyc > 0x3f) -+ return -1; -+ -+ cs_pulse = ps_to_rfbi_ticks(t->cs_pulse_width, div); -+ if (cs_pulse > 0x3f) -+ return -1; -+ -+ l = wecyc; -+ l |= recyc << 6; -+ l |= cs_pulse << 12; -+ l |= actim << 22; -+ -+ t->tim[1] = l; -+ -+ t->tim[2] = div - 1; -+ -+ t->converted = 1; -+ -+ return 0; -+} -+ -+/* xxx FIX module selection missing */ -+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) -+{ -+ int hs, vs; -+ int min; -+ u32 l; -+ -+ hs = ps_to_rfbi_ticks(hs_pulse_time, 1); -+ vs = ps_to_rfbi_ticks(vs_pulse_time, 1); -+ if (hs < 2) -+ return -EDOM; -+ if (mode == OMAP_DSS_RFBI_TE_MODE_2) -+ min = 2; -+ else /* OMAP_DSS_RFBI_TE_MODE_1 */ -+ min = 4; -+ if (vs < min) -+ return -EDOM; -+ if (vs == hs) -+ return -EINVAL; -+ rfbi.te_mode = mode; -+ DSSDBG("setup_te: mode %d hs %d vs %d hs_inv %d vs_inv %d\n", -+ mode, hs, vs, hs_pol_inv, vs_pol_inv); -+ -+ rfbi_enable_clocks(1); -+ rfbi_write_reg(RFBI_HSYNC_WIDTH, hs); -+ rfbi_write_reg(RFBI_VSYNC_WIDTH, vs); -+ -+ l = rfbi_read_reg(RFBI_CONFIG(0)); -+ if (hs_pol_inv) -+ l &= ~(1 << 21); -+ else -+ l |= 1 << 21; -+ if (vs_pol_inv) -+ l &= ~(1 << 20); -+ else -+ l |= 1 << 20; -+ rfbi_enable_clocks(0); -+ -+ return 0; -+} -+EXPORT_SYMBOL(omap_rfbi_setup_te); -+ -+/* xxx FIX module selection missing */ -+int omap_rfbi_enable_te(int enable, unsigned line) -+{ -+ u32 l; -+ -+ DSSDBG("te %d line %d mode %d\n", enable, line, rfbi.te_mode); -+ if (line > (1 << 11) - 1) -+ return -EINVAL; -+ -+ rfbi_enable_clocks(1); -+ l = rfbi_read_reg(RFBI_CONFIG(0)); -+ l &= ~(0x3 << 2); -+ if (enable) { -+ rfbi.te_enabled = 1; -+ l |= rfbi.te_mode << 2; -+ } else -+ rfbi.te_enabled = 0; -+ rfbi_write_reg(RFBI_CONFIG(0), l); -+ rfbi_write_reg(RFBI_LINE_NUMBER, line); -+ rfbi_enable_clocks(0); -+ -+ return 0; -+} -+EXPORT_SYMBOL(omap_rfbi_enable_te); -+ -+#if 0 -+static void rfbi_enable_config(int enable1, int enable2) -+{ -+ u32 l; -+ int cs = 0; -+ -+ if (enable1) -+ cs |= 1<<0; -+ if (enable2) -+ cs |= 1<<1; -+ -+ rfbi_enable_clocks(1); -+ -+ l = rfbi_read_reg(RFBI_CONTROL); -+ -+ l = FLD_MOD(l, cs, 3, 2); -+ l = FLD_MOD(l, 0, 1, 1); -+ -+ rfbi_write_reg(RFBI_CONTROL, l); -+ -+ -+ l = rfbi_read_reg(RFBI_CONFIG(0)); -+ l = FLD_MOD(l, 0, 3, 2); /* TRIGGERMODE: ITE */ -+ /*l |= FLD_VAL(2, 8, 7); */ /* L4FORMAT, 2pix/L4 */ -+ /*l |= FLD_VAL(0, 8, 7); */ /* L4FORMAT, 1pix/L4 */ -+ -+ l = FLD_MOD(l, 0, 16, 16); /* A0POLARITY */ -+ l = FLD_MOD(l, 1, 20, 20); /* TE_VSYNC_POLARITY */ -+ l = FLD_MOD(l, 1, 21, 21); /* HSYNCPOLARITY */ -+ -+ l = FLD_MOD(l, OMAP_DSS_RFBI_PARALLELMODE_8, 1, 0); -+ rfbi_write_reg(RFBI_CONFIG(0), l); -+ -+ rfbi_enable_clocks(0); -+} -+#endif -+ -+int rfbi_configure(int rfbi_module, int bpp, int lines) -+{ -+ u32 l; -+ int cycle1 = 0, cycle2 = 0, cycle3 = 0; -+ enum omap_rfbi_cycleformat cycleformat; -+ enum omap_rfbi_datatype datatype; -+ enum omap_rfbi_parallelmode parallelmode; -+ -+ switch (bpp) { -+ case 12: -+ datatype = OMAP_DSS_RFBI_DATATYPE_12; -+ break; -+ case 16: -+ datatype = OMAP_DSS_RFBI_DATATYPE_16; -+ break; -+ case 18: -+ datatype = OMAP_DSS_RFBI_DATATYPE_18; -+ break; -+ case 24: -+ datatype = OMAP_DSS_RFBI_DATATYPE_24; -+ break; -+ default: -+ BUG(); -+ return 1; -+ } -+ rfbi.datatype = datatype; -+ -+ switch (lines) { -+ case 8: -+ parallelmode = OMAP_DSS_RFBI_PARALLELMODE_8; -+ break; -+ case 9: -+ parallelmode = OMAP_DSS_RFBI_PARALLELMODE_9; -+ break; -+ case 12: -+ parallelmode = OMAP_DSS_RFBI_PARALLELMODE_12; -+ break; -+ case 16: -+ parallelmode = OMAP_DSS_RFBI_PARALLELMODE_16; -+ break; -+ default: -+ BUG(); -+ return 1; -+ } -+ rfbi.parallelmode = parallelmode; -+ -+ if ((bpp % lines) == 0) { -+ switch (bpp / lines) { -+ case 1: -+ cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_1_1; -+ break; -+ case 2: -+ cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_2_1; -+ break; -+ case 3: -+ cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_3_1; -+ break; -+ default: -+ BUG(); -+ return 1; -+ } -+ } else if ((2 * bpp % lines) == 0) { -+ if ((2 * bpp / lines) == 3) -+ cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_3_2; -+ else { -+ BUG(); -+ return 1; -+ } -+ } else { -+ BUG(); -+ return 1; -+ } -+ -+ switch (cycleformat) { -+ case OMAP_DSS_RFBI_CYCLEFORMAT_1_1: -+ cycle1 = lines; -+ break; -+ -+ case OMAP_DSS_RFBI_CYCLEFORMAT_2_1: -+ cycle1 = lines; -+ cycle2 = lines; -+ break; -+ -+ case OMAP_DSS_RFBI_CYCLEFORMAT_3_1: -+ cycle1 = lines; -+ cycle2 = lines; -+ cycle3 = lines; -+ break; -+ -+ case OMAP_DSS_RFBI_CYCLEFORMAT_3_2: -+ cycle1 = lines; -+ cycle2 = (lines / 2) | ((lines / 2) << 16); -+ cycle3 = (lines << 16); -+ break; -+ } -+ -+ rfbi_enable_clocks(1); -+ -+ REG_FLD_MOD(RFBI_CONTROL, 0, 3, 2); /* clear CS */ -+ -+ l = 0; -+ l |= FLD_VAL(parallelmode, 1, 0); -+ l |= FLD_VAL(0, 3, 2); /* TRIGGERMODE: ITE */ -+ l |= FLD_VAL(0, 4, 4); /* TIMEGRANULARITY */ -+ l |= FLD_VAL(datatype, 6, 5); -+ /* l |= FLD_VAL(2, 8, 7); */ /* L4FORMAT, 2pix/L4 */ -+ l |= FLD_VAL(0, 8, 7); /* L4FORMAT, 1pix/L4 */ -+ l |= FLD_VAL(cycleformat, 10, 9); -+ l |= FLD_VAL(0, 12, 11); /* UNUSEDBITS */ -+ l |= FLD_VAL(0, 16, 16); /* A0POLARITY */ -+ l |= FLD_VAL(0, 17, 17); /* REPOLARITY */ -+ l |= FLD_VAL(0, 18, 18); /* WEPOLARITY */ -+ l |= FLD_VAL(0, 19, 19); /* CSPOLARITY */ -+ l |= FLD_VAL(1, 20, 20); /* TE_VSYNC_POLARITY */ -+ l |= FLD_VAL(1, 21, 21); /* HSYNCPOLARITY */ -+ rfbi_write_reg(RFBI_CONFIG(rfbi_module), l); -+ -+ rfbi_write_reg(RFBI_DATA_CYCLE1(rfbi_module), cycle1); -+ rfbi_write_reg(RFBI_DATA_CYCLE2(rfbi_module), cycle2); -+ rfbi_write_reg(RFBI_DATA_CYCLE3(rfbi_module), cycle3); -+ -+ -+ l = rfbi_read_reg(RFBI_CONTROL); -+ l = FLD_MOD(l, rfbi_module+1, 3, 2); /* Select CSx */ -+ l = FLD_MOD(l, 0, 1, 1); /* clear bypass */ -+ rfbi_write_reg(RFBI_CONTROL, l); -+ -+ -+ DSSDBG("RFBI config: bpp %d, lines %d, cycles: 0x%x 0x%x 0x%x\n", -+ bpp, lines, cycle1, cycle2, cycle3); -+ -+ rfbi_enable_clocks(0); -+ -+ return 0; -+} -+EXPORT_SYMBOL(rfbi_configure); -+ -+static int rfbi_find_display(struct omap_display *disp) -+{ -+ if (disp == rfbi.display[0]) -+ return 0; -+ -+ if (disp == rfbi.display[1]) -+ return 1; -+ -+ BUG(); -+ return -1; -+} -+ -+ -+static void signal_fifo_waiters(void) -+{ -+ if (atomic_read(&rfbi.cmd_fifo_full) > 0) { -+ /* DSSDBG("SIGNALING: Fifo not full for waiter!\n"); */ -+ complete(&rfbi.cmd_done); -+ atomic_dec(&rfbi.cmd_fifo_full); -+ } -+} -+ -+/* returns 1 for async op, and 0 for sync op */ -+static int do_update(struct omap_display *display, struct update_region *upd) -+{ -+ int x = upd->x; -+ int y = upd->y; -+ int w = upd->w; -+ int h = upd->h; -+ -+ perf_mark_setup(); -+ -+ if (display->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { -+ /*display->ctrl->enable_te(display, 1); */ -+ dispc_setup_partial_planes(display, &x, &y, &w, &h); -+ } -+ -+#ifdef MEASURE_PERF -+ rfbi.perf_bytes = w * h * 2; /* XXX always 16bit */ -+#endif -+ -+ display->ctrl->setup_update(display, x, y, w, h); -+ -+ if (display->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { -+ rfbi_transfer_area(w, h, NULL, NULL); -+ return 1; -+ } else { -+ struct omap_overlay *ovl; -+ void *addr; -+ int scr_width; -+ -+ ovl = &display->manager->overlays[0]; -+ scr_width = ovl->info.screen_width; -+ addr = ovl->info.vaddr; -+ -+ omap_rfbi_write_pixels(addr, scr_width, x, y, w, h); -+ -+ perf_show("L4"); -+ -+ return 0; -+ } -+} -+ -+static void process_cmd_fifo(void) -+{ -+ int len; -+ struct update_param p; -+ struct omap_display *display; -+ unsigned long flags; -+ -+ if (atomic_inc_return(&rfbi.cmd_pending) != 1) -+ return; -+ -+ while (true) { -+ spin_lock_irqsave(rfbi.cmd_fifo->lock, flags); -+ -+ len = __kfifo_get(rfbi.cmd_fifo, (unsigned char *)&p, -+ sizeof(struct update_param)); -+ if (len == 0) { -+ DSSDBG("nothing more in fifo\n"); -+ atomic_set(&rfbi.cmd_pending, 0); -+ spin_unlock_irqrestore(rfbi.cmd_fifo->lock, flags); -+ break; -+ } -+ -+ /* DSSDBG("fifo full %d\n", rfbi.cmd_fifo_full.counter);*/ -+ -+ spin_unlock_irqrestore(rfbi.cmd_fifo->lock, flags); -+ -+ BUG_ON(len != sizeof(struct update_param)); -+ BUG_ON(p.rfbi_module > 1); -+ -+ display = rfbi.display[p.rfbi_module]; -+ -+ if (p.cmd == RFBI_CMD_UPDATE) { -+ if (do_update(display, &p.par.r)) -+ break; /* async op */ -+ } else if (p.cmd == RFBI_CMD_SYNC) { -+ DSSDBG("Signaling SYNC done!\n"); -+ complete(p.par.sync); -+ } else -+ BUG(); -+ } -+ -+ signal_fifo_waiters(); -+} -+ -+static void rfbi_push_cmd(struct update_param *p) -+{ -+ int ret; -+ -+ while (1) { -+ unsigned long flags; -+ int available; -+ -+ spin_lock_irqsave(rfbi.cmd_fifo->lock, flags); -+ available = RFBI_CMD_FIFO_LEN_BYTES - -+ __kfifo_len(rfbi.cmd_fifo); -+ -+/* DSSDBG("%d bytes left in fifo\n", available); */ -+ if (available < sizeof(struct update_param)) { -+ DSSDBG("Going to wait because FIFO FULL..\n"); -+ spin_unlock_irqrestore(rfbi.cmd_fifo->lock, flags); -+ atomic_inc(&rfbi.cmd_fifo_full); -+ wait_for_completion(&rfbi.cmd_done); -+ /*DSSDBG("Woke up because fifo not full anymore\n");*/ -+ continue; -+ } -+ -+ ret = __kfifo_put(rfbi.cmd_fifo, (unsigned char *)p, -+ sizeof(struct update_param)); -+/* DSSDBG("pushed %d bytes\n", ret);*/ -+ -+ spin_unlock_irqrestore(rfbi.cmd_fifo->lock, flags); -+ -+ BUG_ON(ret != sizeof(struct update_param)); -+ -+ break; -+ } -+} -+ -+static void rfbi_push_update(int rfbi_module, int x, int y, int w, int h) -+{ -+ struct update_param p; -+ -+ p.rfbi_module = rfbi_module; -+ p.cmd = RFBI_CMD_UPDATE; -+ -+ p.par.r.x = x; -+ p.par.r.y = y; -+ p.par.r.w = w; -+ p.par.r.h = h; -+ -+ DSSDBG("RFBI pushed %d,%d %dx%d\n", x, y, w, h); -+ -+ rfbi_push_cmd(&p); -+ -+ process_cmd_fifo(); -+} -+ -+static void rfbi_push_sync(int rfbi_module, struct completion *sync_comp) -+{ -+ struct update_param p; -+ -+ p.rfbi_module = rfbi_module; -+ p.cmd = RFBI_CMD_SYNC; -+ p.par.sync = sync_comp; -+ -+ rfbi_push_cmd(&p); -+ -+ DSSDBG("RFBI sync pushed to cmd fifo\n"); -+ -+ process_cmd_fifo(); -+} -+ -+int rfbi_init(void) -+{ -+ u32 rev; -+ u32 l; -+ -+ spin_lock_init(&rfbi.cmd_lock); -+ rfbi.cmd_fifo = kfifo_alloc(RFBI_CMD_FIFO_LEN_BYTES, GFP_KERNEL, -+ &rfbi.cmd_lock); -+ if (IS_ERR(rfbi.cmd_fifo)) -+ return -ENOMEM; -+ -+ init_completion(&rfbi.cmd_done); -+ atomic_set(&rfbi.cmd_fifo_full, 0); -+ atomic_set(&rfbi.cmd_pending, 0); -+ -+ rfbi.base = ioremap(RFBI_BASE, SZ_256); -+ if (!rfbi.base) { -+ DSSERR("can't ioremap RFBI\n"); -+ return -ENOMEM; -+ } -+ -+ rfbi_enable_clocks(1); -+ -+ msleep(10); -+ -+ rfbi.l4_khz = dss_clk_get_rate(DSS_CLK_ICK) / 1000; -+ -+ /* Enable autoidle and smart-idle */ -+ l = rfbi_read_reg(RFBI_SYSCONFIG); -+ l |= (1 << 0) | (2 << 3); -+ rfbi_write_reg(RFBI_SYSCONFIG, l); -+ -+ rev = rfbi_read_reg(RFBI_REVISION); -+ printk(KERN_INFO "OMAP RFBI rev %d.%d\n", -+ FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); -+ -+ rfbi_enable_clocks(0); -+ -+ return 0; -+} -+ -+void rfbi_exit(void) -+{ -+ DSSDBG("rfbi_exit\n"); -+ -+ kfifo_free(rfbi.cmd_fifo); -+ -+ iounmap(rfbi.base); -+} -+ -+/* struct omap_display support */ -+static int rfbi_display_update(struct omap_display *display, -+ int x, int y, int w, int h) -+{ -+ int rfbi_module; -+ -+ if (w == 0 || h == 0) -+ return 0; -+ -+ rfbi_module = rfbi_find_display(display); -+ -+ rfbi_push_update(rfbi_module, x, y, w, h); -+ -+ return 0; -+} -+ -+static int rfbi_display_sync(struct omap_display *display) -+{ -+ struct completion sync_comp; -+ int rfbi_module; -+ -+ rfbi_module = rfbi_find_display(display); -+ -+ init_completion(&sync_comp); -+ rfbi_push_sync(rfbi_module, &sync_comp); -+ DSSDBG("Waiting for SYNC to happen...\n"); -+ wait_for_completion(&sync_comp); -+ DSSDBG("Released from SYNC\n"); -+ return 0; -+} -+ -+static int rfbi_display_enable_te(struct omap_display *display, int enable) -+{ -+ display->ctrl->enable_te(display, enable); -+ return 0; -+} -+ -+static int rfbi_display_enable(struct omap_display *display) -+{ -+ int r; -+ -+ BUG_ON(display->panel == NULL || display->ctrl == NULL); -+ -+ r = omap_dispc_register_isr(framedone_callback, NULL, -+ DISPC_IRQ_FRAMEDONE); -+ if (r) { -+ DSSERR("can't get FRAMEDONE irq\n"); -+ return r; -+ } -+ -+ dispc_set_lcd_display_type(OMAP_DSS_LCD_DISPLAY_TFT); -+ -+ dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_RFBI); -+ -+ dispc_set_tft_data_lines(display->ctrl->pixel_size); -+ -+ rfbi_configure(display->hw_config.u.rfbi.channel, -+ display->ctrl->pixel_size, -+ display->hw_config.u.rfbi.data_lines); -+ -+ rfbi_set_timings(display->hw_config.u.rfbi.channel, -+ &display->ctrl->timings); -+ -+ -+ if (display->ctrl && display->ctrl->enable) { -+ r = display->ctrl->enable(display); -+ if (r) -+ goto err; -+ } -+ -+ if (display->panel && display->panel->enable) { -+ r = display->panel->enable(display); -+ if (r) -+ goto err; -+ } -+ -+ return 0; -+err: -+ return -ENODEV; -+} -+ -+static void rfbi_display_disable(struct omap_display *display) -+{ -+ display->ctrl->disable(display); -+ omap_dispc_unregister_isr(framedone_callback); -+} -+ -+void rfbi_init_display(struct omap_display *display) -+{ -+ display->enable = rfbi_display_enable; -+ display->disable = rfbi_display_disable; -+ display->update = rfbi_display_update; -+ display->sync = rfbi_display_sync; -+ display->enable_te = rfbi_display_enable_te; -+ -+ rfbi.display[display->hw_config.u.rfbi.channel] = display; -+ -+ display->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE; -+} -diff --git a/arch/arm/plat-omap/dss/sdi.c b/arch/arm/plat-omap/dss/sdi.c -new file mode 100644 -index 0000000..02d549b ---- /dev/null -+++ b/arch/arm/plat-omap/dss/sdi.c -@@ -0,0 +1,174 @@ -+/* -+ * linux/arch/arm/plat-omap/dss/sdi.c -+ * -+ * 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/>. -+ */ -+ -+#define DSS_SUBSYS_NAME "SDI" -+ -+#include <linux/kernel.h> -+#include <linux/clk.h> -+#include <linux/delay.h> -+#include <linux/err.h> -+ -+#include <mach/board.h> -+#include <mach/display.h> -+#include "dss.h" -+ -+ -+static struct { -+ int update_enabled; -+} sdi; -+ -+static int sdi_display_enable(struct omap_display *display) -+{ -+ struct dispc_clock_info cinfo; -+ int lck_div, pck_div; -+ unsigned long fck; -+ struct omap_panel *panel = display->panel; -+ unsigned high, low, burst; -+ unsigned long pck; -+ -+ if (display->state != OMAP_DSS_DISPLAY_DISABLED) { -+ DSSERR("display already enabled\n"); -+ return -EINVAL; -+ } -+ -+ panel->enable(display); -+ -+ dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); -+ -+ dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_BYPASS); -+ -+ dispc_set_burst_size(OMAP_DSS_GFX, OMAP_DSS_BURST_16x32); -+ dispc_set_burst_size(OMAP_DSS_VIDEO1, OMAP_DSS_BURST_16x32); -+ dispc_set_burst_size(OMAP_DSS_VIDEO2, OMAP_DSS_BURST_16x32); -+ -+ burst = 16 * 32 / 8; -+ -+ high = dispc_get_plane_fifo_size(OMAP_DSS_GFX) - burst; -+ low = dispc_get_plane_fifo_size(OMAP_DSS_GFX) / 4 * 3; -+ dispc_setup_plane_fifo(OMAP_DSS_GFX, low, high); -+ -+ high = dispc_get_plane_fifo_size(OMAP_DSS_VIDEO1) - burst; -+ low = dispc_get_plane_fifo_size(OMAP_DSS_VIDEO1) / 4 * 3; -+ dispc_setup_plane_fifo(OMAP_DSS_VIDEO1, low, high); -+ -+ high = dispc_get_plane_fifo_size(OMAP_DSS_VIDEO2) - burst; -+ low = dispc_get_plane_fifo_size(OMAP_DSS_VIDEO2) / 4 * 3; -+ dispc_setup_plane_fifo(OMAP_DSS_VIDEO2, low, high); -+ -+ /* 15.5.9.1.2 */ -+ panel->config |= OMAP_DSS_LCD_RF | OMAP_DSS_LCD_ONOFF; -+ -+ dispc_set_pol_freq(panel); -+ -+ dispc_calc_clock_div(1, panel->timings.pixel_clock * 1000, -+ &cinfo); -+ -+ if (dispc_set_clock_div(&cinfo)) { -+ DSSERR("Failed to set DSS clocks\n"); -+ return -EINVAL; -+ } -+ -+ fck = cinfo.fck; -+ lck_div = cinfo.lck_div; -+ pck_div = cinfo.pck_div; -+ -+ pck = fck / lck_div / pck_div / 1000; -+ -+ if (pck != panel->timings.pixel_clock) { -+ DSSWARN("Could not find exact pixel clock. Requested %d kHz, " -+ "got %lu kHz\n", -+ panel->timings.pixel_clock, pck); -+ -+ panel->timings.pixel_clock = pck; -+ } -+ -+ dispc_set_lcd_timings(&panel->timings); -+ -+ dispc_set_lcd_display_type(OMAP_DSS_LCD_DISPLAY_TFT); -+ dispc_set_tft_data_lines(24); -+ dispc_lcd_enable_signal_polarity(1); -+ dispc_pck_free_enable(1); -+ -+ dss_sdi_init(display->hw_config.u.sdi.datapairs); -+ -+ mdelay(2); -+ -+ dispc_enable_lcd_out(1); -+ -+ display->state = OMAP_DSS_DISPLAY_ACTIVE; -+ -+ return 0; -+} -+ -+static void sdi_display_disable(struct omap_display *display) -+{ -+ if (display->state == OMAP_DSS_DISPLAY_DISABLED) -+ return; -+ -+ display->panel->disable(display); -+ dispc_enable_lcd_out(0); -+ -+ dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); -+ -+ display->state = OMAP_DSS_DISPLAY_DISABLED; -+} -+ -+static int sdi_display_set_update_mode(struct omap_display *display, -+ 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_display *display) -+{ -+ return sdi.update_enabled ? OMAP_DSS_UPDATE_AUTO : -+ OMAP_DSS_UPDATE_DISABLED; -+} -+ -+ -+void sdi_init_display(struct omap_display *display) -+{ -+ DSSDBG("SDI init\n"); -+ -+ display->enable = sdi_display_enable; -+ display->disable = sdi_display_disable; -+ display->set_update_mode = sdi_display_set_update_mode; -+ display->get_update_mode = sdi_display_get_update_mode; -+} -+ -+int sdi_init(void) -+{ -+ return 0; -+} -+ -+void sdi_exit(void) -+{ -+} -diff --git a/arch/arm/plat-omap/dss/venc.c b/arch/arm/plat-omap/dss/venc.c -new file mode 100644 -index 0000000..81319e4 ---- /dev/null -+++ b/arch/arm/plat-omap/dss/venc.c -@@ -0,0 +1,506 @@ -+/* -+ * linux/arch/arm/plat-omap/dss/venc.c -+ * -+ * Copyright (C) 2008 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/clk.h> -+#include <linux/err.h> -+#include <linux/io.h> -+#include <linux/mutex.h> -+#include <linux/completion.h> -+#include <linux/delay.h> -+ -+#include <mach/display.h> -+#include <mach/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_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; -+ -+ int width; -+ int height; -+}; -+ -+/* 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 = 0x00180270, -+ .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, -+ -+ .width = 720, -+ .height = 574, /* for some reason, this isn't 576 */ -+}; -+ -+/* 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, -+ -+ .width = 720, -+ .height = 482, -+}; -+ -+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, -+ -+ .width = 720, -+ .height = 576, -+}; -+ -+static struct { -+ void __iomem *base; -+ const struct venc_config *config; -+ struct mutex venc_lock; -+} venc; -+ -+static struct omap_panel venc_panel = { -+ .name = "tv-out", -+ .bpp = 24, -+}; -+ -+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_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, venc_read_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; -+ } -+ } -+} -+ -+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); -+} -+ -+int venc_init(void) -+{ -+ u8 rev_id; -+ int use_pal = 1; /* XXX */ -+ -+ mutex_init(&venc.venc_lock); -+ -+ if (use_pal) -+ venc.config = &venc_config_pal_trm; -+ else -+ venc.config = &venc_config_ntsc_trm; -+ -+ venc_panel.timings.x_res = venc.config->width; -+ venc_panel.timings.y_res = venc.config->height; -+ -+ venc.base = ioremap(VENC_BASE, SZ_1K); -+ if (!venc.base) { -+ DSSERR("can't ioremap VENC\n"); -+ return -ENOMEM; -+ } -+ -+ /* enable clocks */ -+ venc_enable_clocks(1); -+ -+ /* configure venc */ -+ venc_reset(); -+ venc_write_config(venc.config); -+ -+ 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 0; -+} -+ -+void venc_exit(void) -+{ -+ iounmap(venc.base); -+} -+ -+static void venc_sync_lost_handler(void *arg, u32 mask) -+{ -+ /* we just catch SYNC_LOST_DIGIT here so that -+ * dispc doesn't take it as an error */ -+} -+ -+static int venc_enable_display(struct omap_display *display) -+{ -+ DSSDBG("venc_enable_display\n"); -+ -+ mutex_lock(&venc.venc_lock); -+ -+ if (display->state != OMAP_DSS_DISPLAY_DISABLED) { -+ mutex_unlock(&venc.venc_lock); -+ return -EINVAL; -+ } -+ -+ venc_enable_clocks(1); -+ -+ dss_set_venc_output(display->hw_config.u.venc.type); -+ dss_set_dac_pwrdn_bgz(1); -+ -+ if (display->hw_config.u.venc.type == OMAP_DSS_VENC_TYPE_COMPOSITE) { -+ if (cpu_is_omap24xx()) -+ venc_write_reg(VENC_OUTPUT_CONTROL, 0x2); -+ else -+ venc_write_reg(VENC_OUTPUT_CONTROL, 0xa); -+ } else { /* S-Video */ -+ venc_write_reg(VENC_OUTPUT_CONTROL, 0xd); -+ } -+ -+ venc_write_config(venc.config); -+ -+ dispc_set_digit_size(venc.config->width, venc.config->height/2); -+ -+ if (display->hw_config.panel_enable) -+ display->hw_config.panel_enable(display); -+ -+ dispc_go(OMAP_DSS_CHANNEL_DIGIT); -+ -+ omap_dispc_register_isr(venc_sync_lost_handler, NULL, -+ DISPC_IRQ_SYNC_LOST_DIGIT); -+ -+ dispc_enable_digit_out(1); -+ -+ mdelay(20); -+ -+ omap_dispc_unregister_isr(venc_sync_lost_handler); -+ -+ display->state = OMAP_DSS_DISPLAY_ACTIVE; -+ -+ mutex_unlock(&venc.venc_lock); -+ -+ return 0; -+} -+ -+static void venc_disable_display(struct omap_display *display) -+{ -+ DSSDBG("venc_disable_display\n"); -+ -+ mutex_lock(&venc.venc_lock); -+ -+ if (display->state == OMAP_DSS_DISPLAY_DISABLED) { -+ mutex_unlock(&venc.venc_lock); -+ return; -+ } -+ -+ venc_write_reg(VENC_OUTPUT_CONTROL, 0); -+ dss_set_dac_pwrdn_bgz(0); -+ -+ dispc_enable_digit_out(0); -+ -+ if (display->hw_config.panel_disable) -+ display->hw_config.panel_disable(display); -+ -+ venc_enable_clocks(0); -+ -+ display->state = OMAP_DSS_DISPLAY_DISABLED; -+ -+ mutex_unlock(&venc.venc_lock); -+} -+ -+static void venc_get_timings(struct omap_display *display, -+ struct omap_video_timings *timings) -+{ -+ *timings = venc_panel.timings; -+} -+ -+void venc_init_display(struct omap_display *display) -+{ -+ display->panel = &venc_panel; -+ display->enable = venc_enable_display; -+ display->disable = venc_disable_display; -+ display->get_timings = venc_get_timings; -+} -diff --git a/arch/arm/plat-omap/include/mach/display.h b/arch/arm/plat-omap/include/mach/display.h -new file mode 100644 -index 0000000..49ab00a ---- /dev/null -+++ b/arch/arm/plat-omap/include/mach/display.h -@@ -0,0 +1,462 @@ -+/* -+ * 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 <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) -+ -+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_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_VID_OMAP3 = -+ 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_YUV2 | OMAP_DSS_COLOR_UYVY, -+}; -+ -+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_color_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, -+}; -+ -+struct omap_display; -+struct omap_panel; -+struct omap_ctrl; -+ -+/* 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 *buf, int scr_width, int x, int y, -+ int w, int h); -+int omap_rfbi_enable_te(int 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 */ -+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); -+ -+/* Board specific data */ -+struct omap_display_data { -+ enum omap_display_type type; -+ -+ union { -+ struct { -+ int data_lines; -+ } dpi; -+ -+ struct { -+ int channel; -+ int data_lines; -+ } rfbi; -+ -+ struct { -+ int datapairs; -+ } sdi; -+ -+ struct { -+ int clk_lane; -+ int clk_pol; -+ int data1_lane; -+ int data1_pol; -+ int data2_lane; -+ int data2_pol; -+ unsigned long ddr_clk_hz; -+ } dsi; -+ -+ struct { -+ enum omap_dss_venc_type type; -+ } venc; -+ } u; -+ -+ int panel_reset_gpio; -+ int ctrl_reset_gpio; -+ -+ const char *name; /* for debug */ -+ const char *ctrl_name; -+ const char *panel_name; -+ -+ void *priv; -+ -+ /* platform specific enable/disable */ -+ int (*panel_enable)(struct omap_display *display); -+ void (*panel_disable)(struct omap_display *display); -+ int (*ctrl_enable)(struct omap_display *display); -+ void (*ctrl_disable)(struct omap_display *display); -+ int (*set_backlight)(struct omap_display *display, -+ int level); -+}; -+ -+struct device; -+ -+/* Board specific data */ -+struct omap_dss_platform_data { -+ unsigned (*get_last_off_on_transaction_id)(struct device *dev); -+ int num_displays; -+ struct omap_display_data *displays[]; -+}; -+ -+struct omap_ctrl { -+ struct module *owner; -+ -+ const char *name; -+ -+ int (*init)(struct omap_display *display); -+ void (*cleanup)(struct omap_display *display); -+ int (*enable)(struct omap_display *display); -+ void (*disable)(struct omap_display *display); -+ int (*suspend)(struct omap_display *display); -+ int (*resume)(struct omap_display *display); -+ void (*setup_update)(struct omap_display *display, -+ int x, int y, int w, int h); -+ -+ int (*enable_te)(struct omap_display *display, int enable); -+ -+ int (*rotate)(struct omap_display *display, int rotate); -+ int (*mirror)(struct omap_display *display, int enable); -+ -+ int (*run_test)(struct omap_display *display, int test); -+ -+ int pixel_size; -+ -+ struct rfbi_timings timings; -+ -+ void *priv; -+}; -+ -+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 */ -+ -+}; -+ -+struct omap_panel { -+ struct module *owner; -+ -+ const char *name; -+ -+ int (*init)(struct omap_display *display); -+ void (*cleanup)(struct omap_display *display); -+ int (*remove)(struct omap_display *display); -+ int (*enable)(struct omap_display *display); -+ void (*disable)(struct omap_display *display); -+ int (*suspend)(struct omap_display *display); -+ int (*resume)(struct omap_display *display); -+ int (*run_test)(struct omap_display *display, int test); -+ -+ 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; -+ -+ int bpp; -+ -+ void *priv; -+}; -+ -+/* XXX perhaps this should be removed */ -+enum omap_dss_overlay_managers { -+ OMAP_DSS_OVL_MGR_LCD, -+ OMAP_DSS_OVL_MGR_TV, -+}; -+ -+struct omap_overlay_manager; -+ -+struct omap_overlay_info { -+ int enabled; -+ u32 paddr; -+ void *vaddr; -+ int screen_width; -+ int pos_x; -+ int pos_y; -+ int width; -+ int height; -+ int out_width; /* if 0, out_width == width */ -+ int out_height; /* if 0, out_height == height */ -+ enum omap_color_mode color_mode; -+}; -+ -+enum omap_overlay_caps { -+ OMAP_DSS_OVL_CAP_SCALE = 1 << 0, -+}; -+ -+struct omap_overlay { -+ -+ const char *name; -+ int id; -+ struct omap_overlay_manager *manager; -+ enum omap_color_mode supported_modes; -+ struct omap_overlay_info info; -+ enum omap_overlay_caps caps; -+ -+ int (*set_manager)(struct omap_overlay *ovl, -+ struct omap_overlay_manager *mgr); -+ int (*unset_manager)(struct omap_overlay *ovl); -+ -+ int (*setup_input)(struct omap_overlay *ovl, -+ u32 paddr, void *vaddr, -+ int screen_width, -+ int width, int height, -+ enum omap_color_mode color_mode); -+ int (*setup_output)(struct omap_overlay *ovl, -+ int pos_x, int pos_y, -+ int out_width, int out_height); -+ int (*enable)(struct omap_overlay *ovl, int enable); -+}; -+ -+enum omap_overlay_manager_caps { -+ OMAP_DSS_OVL_MGR_CAP_DISPC = 1 << 0, -+}; -+ -+struct omap_overlay_manager { -+ -+ const char *name; -+ int id; -+ enum omap_overlay_manager_caps caps; -+ struct omap_display *display; -+ int num_overlays; -+ struct omap_overlay *overlays; -+ enum omap_display_type supported_displays; -+ -+ int (*set_display)(struct omap_overlay_manager *mgr, -+ struct omap_display *display); -+ int (*unset_display)(struct omap_overlay_manager *mgr); -+ -+ int (*apply)(struct omap_overlay_manager *mgr); -+}; -+ -+enum omap_display_caps { -+ OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE = 1 << 0, -+}; -+ -+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, -+}; -+ -+struct omap_display { -+ /*atomic_t ref_count;*/ -+ int ref_count; -+ -+ enum omap_display_type type; -+ const char *name; -+ -+ enum omap_display_caps caps; -+ -+ struct omap_overlay_manager *manager; -+ -+ enum omap_dss_display_state state; -+ -+ struct omap_display_data hw_config; /* board specific data */ -+ struct omap_ctrl *ctrl; /* static common data */ -+ struct omap_panel *panel; /* static common data */ -+ -+ int (*enable)(struct omap_display *display); -+ void (*disable)(struct omap_display *display); -+ -+ int (*suspend)(struct omap_display *display); -+ int (*resume)(struct omap_display *display); -+ -+ int (*check_timings)(struct omap_display *display, -+ struct omap_video_timings *timings); -+ void (*set_timings)(struct omap_display *display, -+ struct omap_video_timings *timings); -+ void (*get_timings)(struct omap_display *display, -+ struct omap_video_timings *timings); -+ int (*update)(struct omap_display *display, -+ int x, int y, int w, int h); -+ int (*sync)(struct omap_display *display); -+ -+ int (*set_update_mode)(struct omap_display *display, -+ enum omap_dss_update_mode); -+ enum omap_dss_update_mode (*get_update_mode) -+ (struct omap_display *display); -+ -+ int (*enable_te)(struct omap_display *display, int enable); -+ int (*get_te)(struct omap_display *display); -+ -+ int (*run_test)(struct omap_display *display, int test); -+}; -+ -+int omap_dss_get_num_displays(void); -+struct omap_display *omap_dss_get_display(int no); -+void omap_dss_put_display(struct omap_display *display); -+ -+void omap_dss_register_ctrl(struct omap_ctrl *ctrl); -+void omap_dss_unregister_ctrl(struct omap_ctrl *ctrl); -+ -+void omap_dss_register_panel(struct omap_panel *panel); -+void omap_dss_unregister_panel(struct omap_panel *panel); -+ -+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); -+ -+#endif --- -1.5.6.3 - |