[Armadeus-commitlog] armadeus branch, master, updated. armadeus-4.1-245-g7f8705f
Brought to you by:
sszy
|
From: Julien B a. A. <ar...@us...> - 2012-04-03 16:12:38
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "armadeus".
The branch, master has been updated
via 7f8705fc422e80887e229bc05c3f800d8658e2e4 (commit)
via 5b72626c25951e1b3bdb36ef40bdf5f274944db6 (commit)
via 95ce6ad213c4d10e42a78825b75d064a61e5e7f1 (commit)
from a78dfc0f15e3d66e47443e9b2e54d412e0c92e11 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 7f8705fc422e80887e229bc05c3f800d8658e2e4
Merge: 5b72626 a78dfc0
Author: Julien Boibessot <jul...@ar...>
Date: Tue Apr 3 18:12:08 2012 +0200
Merge branch 'master' of ssh://armadeus.git.sourceforge.net/gitroot/armadeus/armadeus
commit 5b72626c25951e1b3bdb36ef40bdf5f274944db6
Author: Julien Boibessot <jul...@ar...>
Date: Tue Apr 3 18:11:27 2012 +0200
[BUILDROOT] Add gst-fsl-plugin and fsl-mm-codeclib packages
commit 95ce6ad213c4d10e42a78825b75d064a61e5e7f1
Author: Julien Boibessot <jul...@ar...>
Date: Tue Apr 3 18:03:07 2012 +0200
[LINUX] APF51: add Freescale's IPU framebuffer driver (preliminary)
-----------------------------------------------------------------------
Summary of changes:
.../2012.02/174-imx-lib-add_package.patch | 11 +-
.../2012.02/184-fsl-mm-codeclib-add_package.patch | 30 +
.../2012.02/185-gst-fsl-plugin-add_package.patch | 97 +
patches/buildroot/2012.02/cleanup_buildroot.sh | 2 +
...dd_freescale_ipu_based_framebuffer_driver.patch | 3362 ++++++++++++++++++++
5 files changed, 3497 insertions(+), 5 deletions(-)
create mode 100644 patches/buildroot/2012.02/184-fsl-mm-codeclib-add_package.patch
create mode 100644 patches/buildroot/2012.02/185-gst-fsl-plugin-add_package.patch
create mode 100644 patches/linux/2.6.38/447-armadeus-add_freescale_ipu_based_framebuffer_driver.patch
diff --git a/patches/buildroot/2012.02/174-imx-lib-add_package.patch b/patches/buildroot/2012.02/174-imx-lib-add_package.patch
index a590c30..802396a 100644
--- a/patches/buildroot/2012.02/174-imx-lib-add_package.patch
+++ b/patches/buildroot/2012.02/174-imx-lib-add_package.patch
@@ -3,7 +3,7 @@ Signed-off-by: Julien Boibessot <jul...@ar...>
Index: buildroot/package/imx-lib/Config.in
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ buildroot/package/imx-lib/Config.in 2012-03-02 12:03:12.000000000 +0100
++++ buildroot/package/imx-lib/Config.in 2012-04-03 10:31:23.000000000 +0200
@@ -0,0 +1,4 @@
+config BR2_PACKAGE_IMX_LIB
+ bool "imx-lib"
@@ -12,8 +12,8 @@ Index: buildroot/package/imx-lib/Config.in
Index: buildroot/package/imx-lib/imx-lib.mk
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ buildroot/package/imx-lib/imx-lib.mk 2012-03-02 12:13:24.000000000 +0100
-@@ -0,0 +1,45 @@
++++ buildroot/package/imx-lib/imx-lib.mk 2012-04-03 12:24:19.000000000 +0200
+@@ -0,0 +1,46 @@
+#############################################################
+#
+# imx-lib (helpers librairies from Freescale BSP)
@@ -43,6 +43,7 @@ Index: buildroot/package/imx-lib/imx-lib.mk
+ install -D -m 755 $(@D)/vpu/vpu_io.h $(STAGING_DIR)/usr/include
+ install -D -m 755 $(@D)/vpu/vpu_lib.h $(STAGING_DIR)/usr/include
+ install -D -m 755 $(@D)/sahara2/libsahara.so $(STAGING_DIR)/usr/lib
++ install -D -m 755 $(@D)/ipu/mxc_ipu_hl_lib.h $(STAGING_DIR)/usr/include
+endef
+
+define IMX_LIB_INSTALL_TARGET_CMDS
@@ -61,8 +62,8 @@ Index: buildroot/package/imx-lib/imx-lib.mk
+$(eval $(call GENTARGETS))
Index: buildroot/package/Config.in
===================================================================
---- buildroot.orig/package/Config.in 2012-03-02 12:06:29.000000000 +0100
-+++ buildroot/package/Config.in 2012-03-02 12:07:27.000000000 +0100
+--- buildroot.orig/package/Config.in 2012-04-03 10:31:23.000000000 +0200
++++ buildroot/package/Config.in 2012-04-03 18:01:02.000000000 +0200
@@ -349,6 +349,7 @@
endmenu
diff --git a/patches/buildroot/2012.02/184-fsl-mm-codeclib-add_package.patch b/patches/buildroot/2012.02/184-fsl-mm-codeclib-add_package.patch
new file mode 100644
index 0000000..7de6054
--- /dev/null
+++ b/patches/buildroot/2012.02/184-fsl-mm-codeclib-add_package.patch
@@ -0,0 +1,30 @@
+Signed-off-by: Julien Boibessot <jul...@ar...>
+
+Index: buildroot/package/multimedia/fsl-mm-codeclib/fsl-mm-codeclib.mk
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ buildroot/package/multimedia/fsl-mm-codeclib/fsl-mm-codeclib.mk 2012-04-03 17:41:31.000000000 +0200
+@@ -0,0 +1,23 @@
++#############################################################
++#
++# fsl-mm-codeclib (Freescale's multimedia binary (glibc based) codecs)
++# currently some are needed to build gst-fsl-plugins
++#
++#############################################################
++FSL_MM_CODECLIB_VERSION = 2.0.3
++FSL_MM_CODECLIB_SITE = ftp://ftp2.armadeus.com/_downloads
++FSL_MM_CODECLIB_INSTALL_STAGING = YES
++
++define FSL_MM_CODECLIB_INSTALL_STAGING_CMDS
++ cp $(@D)/pkgconfig/*.pc $(STAGING_DIR)/usr/lib/pkgconfig/
++ cp -rf $(@D)/ghdr $(STAGING_DIR)/usr/include/mm_ghdr
++
++ # Needed by software audio PP gstreamer plugin
++ cp $(@D)/release/lib/lib_peq_arm11_elinux.so $(STAGING_DIR)/usr/lib/
++ cd $(STAGING_DIR)/usr/lib/; ln -sf lib_peq_arm11_elinux.so lib_peq_arm11_elinux.so.1.8.0
++
++ # Needed by software deinterlace gstreamer plugin
++ cp $(@D)/release/lib/lib_deinterlace_arm11_elinux.so $(STAGING_DIR)/usr/lib/
++endef
++
++$(eval $(call GENTARGETS))
diff --git a/patches/buildroot/2012.02/185-gst-fsl-plugin-add_package.patch b/patches/buildroot/2012.02/185-gst-fsl-plugin-add_package.patch
new file mode 100644
index 0000000..6d13023
--- /dev/null
+++ b/patches/buildroot/2012.02/185-gst-fsl-plugin-add_package.patch
@@ -0,0 +1,97 @@
+Signed-off-by: Julien Boibessot <jul...@ar...>
+
+Index: buildroot/package/multimedia/gst-fsl-plugin/gst-fsl-plugin.mk
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ buildroot/package/multimedia/gst-fsl-plugin/gst-fsl-plugin.mk 2012-04-03 17:42:39.000000000 +0200
+@@ -0,0 +1,41 @@
++#############################################################
++#
++# gst-fsl-plugin (Freescale's gstreamer custom plugins)
++#
++#############################################################
++GST_FSL_PLUGIN_VERSION = 2.0.3
++GST_FSL_PLUGIN_SITE = ftp://ftp2.armadeus.com/_downloads
++GST_FSL_PLUGIN_INSTALL_STAGING = YES
++
++# if gst-fsl-plugin was better configurable, fsl-mm-codeclib dep could be wiped out
++GST_FSL_PLUGIN_DEPENDENCIES = linux gst-plugins-base imx-lib fsl-mm-codeclib
++
++GST_FSL_PLUGIN_CONF_ENV = CPPFLAGS=-I$(LINUX_DIR)/include
++
++ifeq ($(BR2_CPU_NAME),"imx27")
++GST_FSL_PLUGIN_CONF_OPT = PLATFORM=MX27
++else
++GST_FSL_PLUGIN_CONF_OPT = PLATFORM=MX51
++endif
++GST_FSL_PLUGIN_CONF_OPT += --disable-aac_dec \
++ --disable-aacp_dec \
++ --disable-bsac_dec \
++ --disable-mp3_dec \
++ --disable-mp3_enc \
++ --disable-vorbis_dec \
++ --disable-wma10_dec \
++ --disable-downmix \
++ --disable-wma8_enc \
++ --disable-ac3_dec \
++ --disable-h264_dec \
++ --disable-mpeg4_dec \
++ --disable-mpeg2_dec \
++ --disable-wmv9mp_dec \
++ --disable-wmv78_dec \
++
++define GST_FSL_PLUGIN_NO_IPU_HOOK
++ $(SED) 's/$$(IPUDIRS)//' $(@D)/Makefile
++endef
++GST_FSL_PLUGIN_POST_CONFIGURE_HOOKS += GST_FSL_PLUGIN_NO_IPU_HOOK
++
++$(eval $(call AUTOTARGETS))
+Index: buildroot/package/multimedia/gst-fsl-plugin/gst-fsl-plugin-gst_snapshot_stdio.patch
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ buildroot/package/multimedia/gst-fsl-plugin/gst-fsl-plugin-gst_snapshot_stdio.patch 2012-04-03 17:34:37.000000000 +0200
+@@ -0,0 +1,19 @@
++Otherwise build fails with:
++
++gst_snapshot.c: In function 'gst_save_bmp':
++gst_snapshot.c:241:2: error: 'FILE' undeclared (first use in this function)
++gst_snapshot.c:241:2: note: each undeclared identifier is reported only once for each function it appears in
++gst_snapshot.c:241:9: error: 'fp' undeclared (first use in this function)
++gst_snapshot.c:269:2: warning: incompatible implicit declaration of built-in function 'fwrite'
++
++diff -urN -X linux-2.6.38.8/Documentation/dontdiff gst-fsl-plugin-2.0.3/tools/gplay/gst_snapshot.c gst-fsl-plugin-2.0.3.mod/tools/gplay/gst_snapshot.c
++--- gst-fsl-plugin-2.0.3/tools/gplay/gst_snapshot.c 2011-12-02 07:31:40.000000000 +0100
+++++ gst-fsl-plugin-2.0.3.mod/tools/gplay/gst_snapshot.c 2012-04-03 17:29:35.000000000 +0200
++@@ -21,6 +21,7 @@
++ */
++
++ #include <gst/gst.h>
+++#include <stdio.h>
++ #include <string.h>
++ #include "gst_snapshot.h"
++
+Index: buildroot/package/multimedia/gst-fsl-plugin/Config.in
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ buildroot/package/multimedia/gst-fsl-plugin/Config.in 2012-04-03 17:58:51.000000000 +0200
+@@ -0,0 +1,8 @@
++config BR2_PACKAGE_GST_FSL_PLUGIN
++ bool "gst-fsl-plugin"
++ depends on BR2_PACKAGE_GSTREAMER
++ select BR2_PACKAGE_FSL_MM_CODECLIB
++ select BR2_PACKAGE_GST_PLUGINS_BASE
++ select BR2_PACKAGE_IMX_LIB
++ help
++ Freescale's i.MX specific gstreamer plugins.
+Index: buildroot/package/multimedia/Config.in
+===================================================================
+--- buildroot.orig/package/multimedia/Config.in 2012-04-03 17:54:48.000000000 +0200
++++ buildroot/package/multimedia/Config.in 2012-04-03 17:55:22.000000000 +0200
+@@ -8,6 +8,7 @@
+ source "package/multimedia/ffmpeg/Config.in"
+ source "package/multimedia/gstreamer/Config.in"
+ source "package/multimedia/gst-ffmpeg/Config.in"
++source "package/multimedia/gst-fsl-plugin/Config.in"
+ source "package/multimedia/gst-dsp/Config.in"
+ source "package/multimedia/gst-omapfb/Config.in"
+ source "package/multimedia/gst-plugins-base/Config.in"
diff --git a/patches/buildroot/2012.02/cleanup_buildroot.sh b/patches/buildroot/2012.02/cleanup_buildroot.sh
index 0fcb2c9..a0bcc16 100755
--- a/patches/buildroot/2012.02/cleanup_buildroot.sh
+++ b/patches/buildroot/2012.02/cleanup_buildroot.sh
@@ -68,3 +68,5 @@ rm -rf buildroot/package/imx-lib/
rm -rf buildroot/package/imx-test/
rm -rf buildroot/package/e2fsprogs/
rm -rf buildroot/package/firmware-imx/
+rm -rf buildroot/package/multimedia/gst-fsl-plugin/
+rm -rf buildroot/package/multimedia/fsl-mm-codeclib/
diff --git a/patches/linux/2.6.38/447-armadeus-add_freescale_ipu_based_framebuffer_driver.patch b/patches/linux/2.6.38/447-armadeus-add_freescale_ipu_based_framebuffer_driver.patch
new file mode 100644
index 0000000..2d7ee24
--- /dev/null
+++ b/patches/linux/2.6.38/447-armadeus-add_freescale_ipu_based_framebuffer_driver.patch
@@ -0,0 +1,3362 @@
+As obtained from Freescale's MX53 BSP L2.6.35_11.09.01 + 11.09.01_201112 patches.
+(+ some minor modifications to let them compile on 2.6.38)
+
+Signed-off-by: Julien Boibessot <jul...@ar...>
+
+Index: linux-2.6.38.8/drivers/video/mxc/Kconfig
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.38.8/drivers/video/mxc/Kconfig 2012-04-03 15:27:44.000000000 +0200
+@@ -0,0 +1,115 @@
++menu "Freescale specific framebuffers"
++
++config FB_MXC
++ tristate "MXC Framebuffer support"
++ depends on FB && (MXC_IPU || ARCH_MX21 || ARCH_MX27 || ARCH_MX25)
++ select FB_CFB_FILLRECT
++ select FB_CFB_COPYAREA
++ select FB_CFB_IMAGEBLIT
++ select FB_MODE_HELPERS
++ default y
++ help
++ This is a framebuffer device for the MXC LCD Controller.
++ See <http://www.linux-fbdev.org/> for information on framebuffer
++ devices.
++
++ If you plan to use the LCD display with your MXC system, say
++ Y here.
++
++config FB_MXC_SYNC_PANEL
++ depends on FB_MXC
++ tristate "Synchronous Panel Framebuffer"
++ default y
++
++config FB_MXC_EPSON_VGA_SYNC_PANEL
++ depends on FB_MXC_SYNC_PANEL
++ tristate "Epson VGA Panel"
++ default n
++
++config FB_MXC_TVOUT_TVE
++ tristate "MXC TVE TV Out Encoder"
++ depends on FB_MXC_SYNC_PANEL
++ depends on MXC_IPU_V3
++
++config FB_MXC_LDB
++ tristate "MXC LDB"
++ depends on FB_MXC_SYNC_PANEL
++ depends on MXC_IPU_V3
++
++config FB_MXC_CLAA_WVGA_SYNC_PANEL
++ depends on FB_MXC_SYNC_PANEL
++ tristate "CLAA WVGA Panel"
++
++config FB_MXC_SEIKO_WVGA_SYNC_PANEL
++ depends on FB_MXC_SYNC_PANEL
++ tristate "SEIKO WVGA Panel"
++
++config FB_MXC_SII902X
++ depends on FB_MXC_SYNC_PANEL
++ tristate "Si Image SII9022 DVI/HDMI Interface Chip"
++
++config FB_MXC_CH7026
++ depends on FB_MXC_SYNC_PANEL
++ tristate "Chrontel CH7026 VGA Interface Chip"
++
++config FB_MXC_TVOUT_CH7024
++ tristate "CH7024 TV Out Encoder"
++ depends on FB_MXC_SYNC_PANEL
++
++config FB_MXC_LOW_PWR_DISPLAY
++ bool "Low Power Display Refresh Mode"
++ depends on FB_MXC_SYNC_PANEL && MXC_FB_IRAM
++ default y
++
++config FB_MXC_INTERNAL_MEM
++ bool "Framebuffer in Internal RAM"
++ depends on FB_MXC_SYNC_PANEL && MXC_FB_IRAM
++ default y
++
++config FB_MXC_ASYNC_PANEL
++ depends on FB_MXC
++ bool "Asynchronous Panels"
++ default n
++
++menu "Asynchronous Panel Type"
++ depends on FB_MXC_ASYNC_PANEL && FB_MXC
++
++config FB_MXC_EPSON_PANEL
++ depends on FB_MXC_ASYNC_PANEL
++ default n
++ bool "Epson 176x220 Panel"
++
++endmenu
++
++config FB_MXC_EINK_PANEL
++ depends on FB_MXC
++ depends on DMA_ENGINE
++ select FB_DEFERRED_IO
++ tristate "E-Ink Panel Framebuffer"
++
++config FB_MXC_EINK_AUTO_UPDATE_MODE
++ bool "E-Ink Auto-update Mode Support"
++ default n
++ depends on FB_MXC_EINK_PANEL
++
++config FB_MXC_ELCDIF_FB
++ depends on FB && ARCH_MXC
++ tristate "Support MXC ELCDIF framebuffer"
++
++choice
++ prompt "Async Panel Interface Type"
++ depends on FB_MXC_ASYNC_PANEL && FB_MXC
++ default FB_MXC_ASYNC_PANEL_IFC_16_BIT
++
++config FB_MXC_ASYNC_PANEL_IFC_8_BIT
++ bool "8-bit Parallel Bus Interface"
++
++config FB_MXC_ASYNC_PANEL_IFC_16_BIT
++ bool "16-bit Parallel Bus Interface"
++
++config FB_MXC_ASYNC_PANEL_IFC_SERIAL
++ bool "Serial Bus Interface"
++
++endchoice
++
++endmenu
+Index: linux-2.6.38.8/drivers/video/mxc/Makefile
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.38.8/drivers/video/mxc/Makefile 2012-04-03 14:35:09.000000000 +0200
+@@ -0,0 +1,26 @@
++obj-$(CONFIG_FB_MXC_TVOUT_TVE) += tve.o
++obj-$(CONFIG_FB_MXC_SII902X) += mxcfb_sii902x.o
++obj-$(CONFIG_FB_MXC_LDB) += ldb.o
++obj-$(CONFIG_FB_MODE_HELPERS) += mxc_edid.o mxc_ddc.o
++ifeq ($(CONFIG_ARCH_MX21)$(CONFIG_ARCH_MX27)$(CONFIG_ARCH_MX25),y)
++ obj-$(CONFIG_FB_MXC_TVOUT) += fs453.o
++ obj-$(CONFIG_FB_MXC_SYNC_PANEL) += mx2fb.o mxcfb_modedb.o
++ obj-$(CONFIG_FB_MXC_EPSON_PANEL) += mx2fb_epson.o
++else
++ifeq ($(CONFIG_MXC_IPU_V1),y)
++ obj-$(CONFIG_FB_MXC_SYNC_PANEL) += mxcfb.o mxcfb_modedb.o
++else
++ obj-$(CONFIG_FB_MXC_SYNC_PANEL) += mxc_ipuv3_fb.o
++endif
++ obj-$(CONFIG_FB_MXC_EPSON_PANEL) += mxcfb_epson.o
++ obj-$(CONFIG_FB_MXC_EPSON_QVGA_PANEL) += mxcfb_epson_qvga.o
++ obj-$(CONFIG_FB_MXC_TOSHIBA_QVGA_PANEL) += mxcfb_toshiba_qvga.o
++ obj-$(CONFIG_FB_MXC_SHARP_128_PANEL) += mxcfb_sharp_128x128.o
++endif
++obj-$(CONFIG_FB_MXC_EPSON_VGA_SYNC_PANEL) += mxcfb_epson_vga.o
++obj-$(CONFIG_FB_MXC_CLAA_WVGA_SYNC_PANEL) += mxcfb_claa_wvga.o
++obj-$(CONFIG_FB_MXC_SEIKO_WVGA_SYNC_PANEL) += mxcfb_seiko_wvga.o
++obj-$(CONFIG_FB_MXC_TVOUT_CH7024) += ch7024.o
++obj-$(CONFIG_FB_MXC_CH7026) += mxcfb_ch7026.o
++obj-$(CONFIG_FB_MXC_EINK_PANEL) += mxc_epdc_fb.o
++obj-$(CONFIG_FB_MXC_ELCDIF_FB) += mxc_elcdif_fb.o
+Index: linux-2.6.38.8/drivers/video/mxc/mxc_ipuv3_fb.c
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.38.8/drivers/video/mxc/mxc_ipuv3_fb.c 2012-04-03 16:25:43.000000000 +0200
+@@ -0,0 +1,2091 @@
++/*
++ * Copyright 2004-2011 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*!
++ * @defgroup Framebuffer Framebuffer Driver for SDC and ADC.
++ */
++
++/*!
++ * @file mxcfb.c
++ *
++ * @brief MXC Frame buffer driver for SDC
++ *
++ * @ingroup Framebuffer
++ */
++
++/*!
++ * Include files
++ */
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/platform_device.h>
++#include <linux/sched.h>
++#include <linux/errno.h>
++#include <linux/string.h>
++#include <linux/interrupt.h>
++#include <linux/slab.h>
++#include <linux/fb.h>
++#include <linux/delay.h>
++#include <linux/init.h>
++#include <linux/ioport.h>
++#include <linux/dma-mapping.h>
++#include <linux/clk.h>
++#include <linux/console.h>
++#include <linux/io.h>
++#include <linux/ipu.h>
++#include <linux/mxcfb.h>
++#include <linux/uaccess.h>
++#include <linux/fsl_devices.h>
++#include <asm/mach-types.h>
++
++/*
++ * Driver name
++ */
++#define MXCFB_NAME "mxc_sdc_fb"
++
++/* Display port number */
++#define MXCFB_PORT_NUM 2
++/*!
++ * Structure containing the MXC specific framebuffer information.
++ */
++struct mxcfb_info {
++ char *fb_mode_str;
++ int default_bpp;
++ int cur_blank;
++ int next_blank;
++ ipu_channel_t ipu_ch;
++ int ipu_di;
++ u32 ipu_di_pix_fmt;
++ bool ipu_int_clk;
++ bool overlay;
++ bool alpha_chan_en;
++ dma_addr_t alpha_phy_addr0;
++ dma_addr_t alpha_phy_addr1;
++ void *alpha_virt_addr0;
++ void *alpha_virt_addr1;
++ uint32_t alpha_mem_len;
++ uint32_t ipu_ch_irq;
++ uint32_t ipu_alp_ch_irq;
++ uint32_t cur_ipu_buf;
++ uint32_t cur_ipu_alpha_buf;
++
++ u32 pseudo_palette[16];
++
++ bool wait4vsync;
++ struct semaphore flip_sem;
++ struct semaphore alpha_flip_sem;
++ struct completion vsync_complete;
++
++ bool fb_suspended;
++};
++
++struct mxcfb_mode {
++ int dev_mode;
++ int num_modes;
++ struct fb_videomode *mode;
++};
++
++struct mxcfb_alloc_list {
++ struct list_head list;
++ dma_addr_t phy_addr;
++ void *cpu_addr;
++ u32 size;
++};
++
++enum {
++ BOTH_ON,
++ SRC_ON,
++ TGT_ON,
++ BOTH_OFF
++};
++
++static bool g_dp_in_use;
++LIST_HEAD(fb_alloc_list);
++static struct fb_info *mxcfb_info[3];
++static struct mxcfb_mode mxc_disp_mode[MXCFB_PORT_NUM];
++static int (*mxcfb_pre_setup[MXCFB_PORT_NUM])(struct fb_info *info);
++
++/*
++ * register pre-setup callback for some display
++ * driver which need prepare clk etc.
++ */
++void mxcfb_register_presetup(int disp_port,
++ int (*pre_setup)(struct fb_info *info))
++{
++ if (pre_setup)
++ mxcfb_pre_setup[disp_port] = pre_setup;
++}
++EXPORT_SYMBOL(mxcfb_register_presetup);
++
++/*
++ * mode register from each display driver before
++ * primary fb setting.
++ */
++void mxcfb_register_mode(int disp_port,
++ const struct fb_videomode *modedb,
++ int num_modes, int dev_mode)
++{
++ struct fb_videomode *mode;
++ int mode_sum;
++
++ if (disp_port > MXCFB_PORT_NUM)
++ return;
++
++ /*
++ * if there is new DDC device, overwrite old modes.
++ * if there is old DDC device while new device is not DDC,
++ * just keep old DDC modes.
++ */
++ if (dev_mode & MXC_DISP_DDC_DEV) {
++ if (mxc_disp_mode[disp_port].num_modes) {
++ kfree(mxc_disp_mode[disp_port].mode);
++ mxc_disp_mode[disp_port].num_modes = 0;
++ }
++ } else if (mxc_disp_mode[disp_port].dev_mode & MXC_DISP_DDC_DEV)
++ return;
++
++ mode_sum = mxc_disp_mode[disp_port].num_modes + num_modes;
++ mode = kzalloc(mode_sum * sizeof(struct fb_videomode), GFP_KERNEL);
++
++ if (mxc_disp_mode[disp_port].num_modes)
++ memcpy(mode, mxc_disp_mode[disp_port].mode,
++ mxc_disp_mode[disp_port].num_modes
++ * sizeof(struct fb_videomode));
++ if (modedb)
++ memcpy(mode + mxc_disp_mode[disp_port].num_modes,
++ modedb, num_modes * sizeof(struct fb_videomode));
++
++ if (mxc_disp_mode[disp_port].num_modes)
++ kfree(mxc_disp_mode[disp_port].mode);
++
++ mxc_disp_mode[disp_port].mode = mode;
++ mxc_disp_mode[disp_port].num_modes += num_modes;
++ mxc_disp_mode[disp_port].dev_mode = dev_mode;
++
++ return;
++}
++EXPORT_SYMBOL(mxcfb_register_mode);
++
++static uint32_t bpp_to_pixfmt(struct fb_info *fbi)
++{
++ uint32_t pixfmt = 0;
++
++ if (fbi->var.nonstd)
++ return fbi->var.nonstd;
++
++ switch (fbi->var.bits_per_pixel) {
++ case 24:
++ pixfmt = IPU_PIX_FMT_BGR24;
++ break;
++ case 32:
++ pixfmt = IPU_PIX_FMT_BGR32;
++ break;
++ case 16:
++ pixfmt = IPU_PIX_FMT_RGB565;
++ break;
++ }
++ return pixfmt;
++}
++
++static irqreturn_t mxcfb_irq_handler(int irq, void *dev_id);
++static int mxcfb_blank(int blank, struct fb_info *info);
++static int mxcfb_map_video_memory(struct fb_info *fbi);
++static int mxcfb_unmap_video_memory(struct fb_info *fbi);
++static int mxcfb_option_setup(struct fb_info *info, char *options);
++
++/*
++ * Set fixed framebuffer parameters based on variable settings.
++ *
++ * @param info framebuffer information pointer
++ */
++static int mxcfb_set_fix(struct fb_info *info)
++{
++ struct fb_fix_screeninfo *fix = &info->fix;
++ struct fb_var_screeninfo *var = &info->var;
++
++ fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
++
++ fix->type = FB_TYPE_PACKED_PIXELS;
++ fix->accel = FB_ACCEL_NONE;
++ fix->visual = FB_VISUAL_TRUECOLOR;
++ fix->xpanstep = 0;
++ fix->ywrapstep = 1;
++ fix->ypanstep = 1;
++
++ return 0;
++}
++
++static int _setup_disp_channel1(struct fb_info *fbi)
++{
++ ipu_channel_params_t params;
++ struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
++
++ memset(¶ms, 0, sizeof(params));
++ params.mem_dp_bg_sync.di = mxc_fbi->ipu_di;
++
++ /*
++ * Assuming interlaced means yuv output, below setting also
++ * valid for mem_dc_sync. FG should have the same vmode as BG.
++ */
++ if (mxc_fbi->ipu_ch == MEM_FG_SYNC) {
++ struct mxcfb_info *mxc_fbi_tmp;
++ int i;
++
++ for (i = 0; i < num_registered_fb; i++) {
++ mxc_fbi_tmp = (struct mxcfb_info *)
++ (registered_fb[i]->par);
++ if (mxc_fbi_tmp->ipu_ch == MEM_BG_SYNC) {
++ fbi->var.vmode =
++ registered_fb[i]->var.vmode;
++ mxc_fbi->ipu_di_pix_fmt =
++ mxc_fbi_tmp->ipu_di_pix_fmt;
++ break;
++ }
++ }
++ }
++ if (mxc_fbi->ipu_ch == MEM_DC_SYNC) {
++ if (fbi->var.vmode & FB_VMODE_INTERLACED) {
++ params.mem_dc_sync.interlaced = true;
++ params.mem_dc_sync.out_pixel_fmt =
++ IPU_PIX_FMT_YUV444;
++ } else {
++ if (mxc_fbi->ipu_di_pix_fmt)
++ params.mem_dc_sync.out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt;
++ else
++ params.mem_dc_sync.out_pixel_fmt = IPU_PIX_FMT_RGB666;
++ }
++ params.mem_dc_sync.in_pixel_fmt = bpp_to_pixfmt(fbi);
++ } else {
++ if (fbi->var.vmode & FB_VMODE_INTERLACED) {
++ params.mem_dp_bg_sync.interlaced = true;
++ params.mem_dp_bg_sync.out_pixel_fmt =
++ IPU_PIX_FMT_YUV444;
++ } else {
++ if (mxc_fbi->ipu_di_pix_fmt)
++ params.mem_dp_bg_sync.out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt;
++ else
++ params.mem_dp_bg_sync.out_pixel_fmt = IPU_PIX_FMT_RGB666;
++ }
++ params.mem_dp_bg_sync.in_pixel_fmt = bpp_to_pixfmt(fbi);
++ if (mxc_fbi->alpha_chan_en)
++ params.mem_dp_bg_sync.alpha_chan_en = true;
++ }
++ ipu_init_channel(mxc_fbi->ipu_ch, ¶ms);
++
++ return 0;
++}
++
++static int _setup_disp_channel2(struct fb_info *fbi)
++{
++ int retval = 0;
++ struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
++ int fb_stride;
++ unsigned long base;
++
++ switch (bpp_to_pixfmt(fbi)) {
++ case IPU_PIX_FMT_YUV420P2:
++ case IPU_PIX_FMT_YVU420P:
++ case IPU_PIX_FMT_NV12:
++ case IPU_PIX_FMT_YUV422P:
++ case IPU_PIX_FMT_YVU422P:
++ case IPU_PIX_FMT_YUV420P:
++ fb_stride = fbi->var.xres_virtual;
++ break;
++ default:
++ fb_stride = fbi->fix.line_length;
++ }
++
++ mxc_fbi->cur_ipu_buf = 2;
++ sema_init(&mxc_fbi->flip_sem, 1);
++ if (mxc_fbi->alpha_chan_en) {
++ mxc_fbi->cur_ipu_alpha_buf = 1;
++ sema_init(&mxc_fbi->alpha_flip_sem, 1);
++ }
++ fbi->var.xoffset = 0;
++
++ base = (fbi->var.yoffset * fbi->var.xres_virtual + fbi->var.xoffset);
++ base = (fbi->var.bits_per_pixel) * base / 8;
++ base += fbi->fix.smem_start;
++
++ retval = ipu_init_channel_buffer(mxc_fbi->ipu_ch, IPU_INPUT_BUFFER,
++ bpp_to_pixfmt(fbi),
++ fbi->var.xres, fbi->var.yres,
++ fb_stride,
++ IPU_ROTATE_NONE,
++ base,
++ base,
++ (fbi->var.accel_flags ==
++ FB_ACCEL_TRIPLE_FLAG) ? base : 0,
++ 0, 0);
++ if (retval) {
++ dev_err(fbi->device,
++ "ipu_init_channel_buffer error %d\n", retval);
++ }
++
++ if (mxc_fbi->alpha_chan_en) {
++ retval = ipu_init_channel_buffer(mxc_fbi->ipu_ch,
++ IPU_ALPHA_IN_BUFFER,
++ IPU_PIX_FMT_GENERIC,
++ fbi->var.xres, fbi->var.yres,
++ fbi->var.xres,
++ IPU_ROTATE_NONE,
++ mxc_fbi->alpha_phy_addr1,
++ mxc_fbi->alpha_phy_addr0,
++ 0,
++ 0, 0);
++ if (retval) {
++ dev_err(fbi->device,
++ "ipu_init_channel_buffer error %d\n", retval);
++ return retval;
++ }
++ }
++
++ return retval;
++}
++
++/*
++ * Set framebuffer parameters and change the operating mode.
++ *
++ * @param info framebuffer information pointer
++ */
++static int mxcfb_set_par(struct fb_info *fbi)
++{
++ int retval = 0;
++ u32 mem_len, alpha_mem_len;
++ ipu_di_signal_cfg_t sig_cfg;
++ struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
++
++ dev_dbg(fbi->device, "Reconfiguring framebuffer\n");
++
++ ipu_disable_irq(mxc_fbi->ipu_ch_irq);
++ ipu_disable_channel(mxc_fbi->ipu_ch, true);
++ ipu_uninit_channel(mxc_fbi->ipu_ch);
++ ipu_clear_irq(mxc_fbi->ipu_ch_irq);
++ mxcfb_set_fix(fbi);
++
++ mem_len = fbi->var.yres_virtual * fbi->fix.line_length;
++ if (!fbi->fix.smem_start || (mem_len > fbi->fix.smem_len)) {
++ if (fbi->fix.smem_start)
++ mxcfb_unmap_video_memory(fbi);
++
++ if (mxcfb_map_video_memory(fbi) < 0)
++ return -ENOMEM;
++ }
++ if (mxc_fbi->alpha_chan_en) {
++ alpha_mem_len = fbi->var.xres * fbi->var.yres;
++ if ((!mxc_fbi->alpha_phy_addr0 && !mxc_fbi->alpha_phy_addr1) ||
++ (alpha_mem_len > mxc_fbi->alpha_mem_len)) {
++ if (mxc_fbi->alpha_phy_addr0)
++ dma_free_coherent(fbi->device,
++ mxc_fbi->alpha_mem_len,
++ mxc_fbi->alpha_virt_addr0,
++ mxc_fbi->alpha_phy_addr0);
++ if (mxc_fbi->alpha_phy_addr1)
++ dma_free_coherent(fbi->device,
++ mxc_fbi->alpha_mem_len,
++ mxc_fbi->alpha_virt_addr1,
++ mxc_fbi->alpha_phy_addr1);
++
++ mxc_fbi->alpha_virt_addr0 =
++ dma_alloc_coherent(fbi->device,
++ alpha_mem_len,
++ &mxc_fbi->alpha_phy_addr0,
++ GFP_DMA | GFP_KERNEL);
++
++ mxc_fbi->alpha_virt_addr1 =
++ dma_alloc_coherent(fbi->device,
++ alpha_mem_len,
++ &mxc_fbi->alpha_phy_addr1,
++ GFP_DMA | GFP_KERNEL);
++ if (mxc_fbi->alpha_virt_addr0 == NULL ||
++ mxc_fbi->alpha_virt_addr1 == NULL) {
++ dev_err(fbi->device, "mxcfb: dma alloc for"
++ " alpha buffer failed.\n");
++ if (mxc_fbi->alpha_virt_addr0)
++ dma_free_coherent(fbi->device,
++ mxc_fbi->alpha_mem_len,
++ mxc_fbi->alpha_virt_addr0,
++ mxc_fbi->alpha_phy_addr0);
++ if (mxc_fbi->alpha_virt_addr1)
++ dma_free_coherent(fbi->device,
++ mxc_fbi->alpha_mem_len,
++ mxc_fbi->alpha_virt_addr1,
++ mxc_fbi->alpha_phy_addr1);
++ return -ENOMEM;
++ }
++ mxc_fbi->alpha_mem_len = alpha_mem_len;
++ }
++ }
++
++ if (mxc_fbi->next_blank != FB_BLANK_UNBLANK ||
++ mxc_fbi->fb_suspended)
++ return retval;
++
++ _setup_disp_channel1(fbi);
++
++ if (!mxc_fbi->overlay) {
++ uint32_t out_pixel_fmt;
++
++ memset(&sig_cfg, 0, sizeof(sig_cfg));
++ if (fbi->var.vmode & FB_VMODE_INTERLACED) {
++ sig_cfg.interlaced = true;
++ out_pixel_fmt = IPU_PIX_FMT_YUV444;
++ } else {
++ if (mxc_fbi->ipu_di_pix_fmt)
++ out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt;
++ else
++ out_pixel_fmt = IPU_PIX_FMT_RGB666;
++ }
++ if (fbi->var.vmode & FB_VMODE_ODD_FLD_FIRST) /* PAL */
++ sig_cfg.odd_field_first = true;
++ if (mxc_fbi->ipu_int_clk)
++ sig_cfg.int_clk = true;
++ if (fbi->var.sync & FB_SYNC_HOR_HIGH_ACT)
++ sig_cfg.Hsync_pol = true;
++ if (fbi->var.sync & FB_SYNC_VERT_HIGH_ACT)
++ sig_cfg.Vsync_pol = true;
++ if (!(fbi->var.sync & FB_SYNC_CLK_LAT_FALL))
++ sig_cfg.clk_pol = true;
++ if (fbi->var.sync & FB_SYNC_DATA_INVERT)
++ sig_cfg.data_pol = true;
++ if (!(fbi->var.sync & FB_SYNC_OE_LOW_ACT))
++ sig_cfg.enable_pol = true;
++ if (fbi->var.sync & FB_SYNC_CLK_IDLE_EN)
++ sig_cfg.clkidle_en = true;
++
++ dev_dbg(fbi->device, "pixclock = %ul Hz\n",
++ (u32) (PICOS2KHZ(fbi->var.pixclock) * 1000UL));
++
++ if (ipu_init_sync_panel(mxc_fbi->ipu_di,
++ (PICOS2KHZ(fbi->var.pixclock)) * 1000UL,
++ fbi->var.xres, fbi->var.yres,
++ out_pixel_fmt,
++ fbi->var.left_margin,
++ fbi->var.hsync_len,
++ fbi->var.right_margin,
++ fbi->var.upper_margin,
++ fbi->var.vsync_len,
++ fbi->var.lower_margin,
++ 0, sig_cfg) != 0) {
++ dev_err(fbi->device,
++ "mxcfb: Error initializing panel.\n");
++ return -EINVAL;
++ }
++
++ fbi->mode =
++ (struct fb_videomode *)fb_match_mode(&fbi->var,
++ &fbi->modelist);
++
++ ipu_disp_set_window_pos(mxc_fbi->ipu_ch, 0, 0);
++ }
++
++ retval = _setup_disp_channel2(fbi);
++ if (retval)
++ return retval;
++
++ ipu_enable_channel(mxc_fbi->ipu_ch);
++
++ mxc_fbi->cur_blank = FB_BLANK_UNBLANK;
++
++ return retval;
++}
++
++static int _swap_channels(struct fb_info *fbi,
++ struct fb_info *fbi_to, bool both_on)
++{
++ int retval, tmp;
++ ipu_channel_t old_ch;
++ struct mxcfb_info *mxc_fbi_from = (struct mxcfb_info *)fbi->par;
++ struct mxcfb_info *mxc_fbi_to = (struct mxcfb_info *)fbi_to->par;
++
++ if (both_on) {
++ ipu_disable_channel(mxc_fbi_to->ipu_ch, true);
++ ipu_uninit_channel(mxc_fbi_to->ipu_ch);
++ }
++
++ /* switch the mxc fbi parameters */
++ old_ch = mxc_fbi_from->ipu_ch;
++ mxc_fbi_from->ipu_ch = mxc_fbi_to->ipu_ch;
++ mxc_fbi_to->ipu_ch = old_ch;
++ tmp = mxc_fbi_from->ipu_ch_irq;
++ mxc_fbi_from->ipu_ch_irq = mxc_fbi_to->ipu_ch_irq;
++ mxc_fbi_to->ipu_ch_irq = tmp;
++
++ _setup_disp_channel1(fbi);
++ retval = _setup_disp_channel2(fbi);
++ if (retval)
++ return retval;
++
++ /* switch between dp and dc, disable old idmac, enable new idmac */
++ retval = ipu_swap_channel(old_ch, mxc_fbi_from->ipu_ch);
++ ipu_uninit_channel(old_ch);
++
++ if (both_on) {
++ _setup_disp_channel1(fbi_to);
++ retval = _setup_disp_channel2(fbi_to);
++ if (retval)
++ return retval;
++ ipu_enable_channel(mxc_fbi_to->ipu_ch);
++ }
++
++ return retval;
++}
++
++static int swap_channels(struct fb_info *fbi)
++{
++ int i;
++ int swap_mode;
++ ipu_channel_t ch_to;
++ struct mxcfb_info *mxc_fbi_from = (struct mxcfb_info *)fbi->par;
++ struct fb_info *fbi_to = NULL;
++ struct mxcfb_info *mxc_fbi_to;
++
++ /* what's the target channel? */
++ if (mxc_fbi_from->ipu_ch == MEM_BG_SYNC)
++ ch_to = MEM_DC_SYNC;
++ else
++ ch_to = MEM_BG_SYNC;
++
++ for (i = 0; i < num_registered_fb; i++) {
++ mxc_fbi_to =
++ (struct mxcfb_info *)mxcfb_info[i]->par;
++ if (mxc_fbi_to->ipu_ch == ch_to) {
++ fbi_to = mxcfb_info[i];
++ break;
++ }
++ }
++ if (fbi_to == NULL)
++ return -1;
++
++ ipu_clear_irq(mxc_fbi_from->ipu_ch_irq);
++ ipu_clear_irq(mxc_fbi_to->ipu_ch_irq);
++ ipu_free_irq(mxc_fbi_from->ipu_ch_irq, fbi);
++ ipu_free_irq(mxc_fbi_to->ipu_ch_irq, fbi_to);
++
++ if (mxc_fbi_from->cur_blank == FB_BLANK_UNBLANK) {
++ if (mxc_fbi_to->cur_blank == FB_BLANK_UNBLANK)
++ swap_mode = BOTH_ON;
++ else
++ swap_mode = SRC_ON;
++ } else {
++ if (mxc_fbi_to->cur_blank == FB_BLANK_UNBLANK)
++ swap_mode = TGT_ON;
++ else
++ swap_mode = BOTH_OFF;
++ }
++
++ /* tvout di-1: for DC use UYVY, for DP use RGB */
++ if (mxc_fbi_from->ipu_di == 1 && ch_to == MEM_DC_SYNC) {
++ fbi->var.bits_per_pixel = 16;
++ fbi->var.nonstd = IPU_PIX_FMT_UYVY;
++ } else if (mxc_fbi_from->ipu_di == 1 && ch_to == MEM_BG_SYNC) {
++ fbi->var.nonstd = 0;
++ } else if (mxc_fbi_from->ipu_di == 0 && ch_to == MEM_DC_SYNC) {
++ fbi_to->var.nonstd = 0;
++ } else if (mxc_fbi_from->ipu_di == 0 && ch_to == MEM_BG_SYNC) {
++ fbi->var.bits_per_pixel = 16;
++ fbi->var.nonstd = IPU_PIX_FMT_UYVY;
++ }
++
++ switch (swap_mode) {
++ case BOTH_ON:
++ /* disable target->switch src->enable target */
++ _swap_channels(fbi, fbi_to, true);
++ break;
++ case SRC_ON:
++ /* just switch src */
++ _swap_channels(fbi, fbi_to, false);
++ break;
++ case TGT_ON:
++ /* just switch target */
++ _swap_channels(fbi_to, fbi, false);
++ break;
++ case BOTH_OFF:
++ /* switch directly, no more need to do */
++ mxc_fbi_to->ipu_ch = mxc_fbi_from->ipu_ch;
++ mxc_fbi_from->ipu_ch = ch_to;
++ i = mxc_fbi_from->ipu_ch_irq;
++ mxc_fbi_from->ipu_ch_irq = mxc_fbi_to->ipu_ch_irq;
++ mxc_fbi_to->ipu_ch_irq = i;
++ break;
++ default:
++ break;
++ }
++
++ if (ipu_request_irq(mxc_fbi_from->ipu_ch_irq, mxcfb_irq_handler, 0,
++ MXCFB_NAME, fbi) != 0) {
++ dev_err(fbi->device, "Error registering irq %d\n",
++ mxc_fbi_from->ipu_ch_irq);
++ return -EBUSY;
++ }
++ ipu_disable_irq(mxc_fbi_from->ipu_ch_irq);
++ if (ipu_request_irq(mxc_fbi_to->ipu_ch_irq, mxcfb_irq_handler, 0,
++ MXCFB_NAME, fbi_to) != 0) {
++ dev_err(fbi_to->device, "Error registering irq %d\n",
++ mxc_fbi_to->ipu_ch_irq);
++ return -EBUSY;
++ }
++ ipu_disable_irq(mxc_fbi_to->ipu_ch_irq);
++
++ return 0;
++}
++
++/*
++ * Check framebuffer variable parameters and adjust to valid values.
++ *
++ * @param var framebuffer variable parameters
++ *
++ * @param info framebuffer information pointer
++ */
++static int mxcfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
++{
++ u32 vtotal;
++ u32 htotal;
++ struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)info->par;
++
++ /* fg should not bigger than bg */
++ if (mxc_fbi->ipu_ch == MEM_FG_SYNC) {
++ struct fb_info *fbi_tmp;
++ struct mxcfb_info *mxc_fbi_tmp;
++ int i, bg_xres, bg_yres;
++ int16_t pos_x, pos_y;
++
++ bg_xres = var->xres;
++ bg_yres = var->yres;
++
++ for (i = 0; i < num_registered_fb; i++) {
++ fbi_tmp = registered_fb[i];
++ mxc_fbi_tmp = (struct mxcfb_info *)
++ (fbi_tmp->par);
++ if (mxc_fbi_tmp->ipu_ch == MEM_BG_SYNC) {
++ bg_xres = fbi_tmp->var.xres;
++ bg_yres = fbi_tmp->var.yres;
++ break;
++ }
++ }
++
++ ipu_disp_get_window_pos(mxc_fbi->ipu_ch, &pos_x, &pos_y);
++
++ if ((var->xres + pos_x) > bg_xres)
++ var->xres = bg_xres - pos_x;
++ if ((var->yres + pos_y) > bg_yres)
++ var->yres = bg_yres - pos_y;
++ }
++
++ if (var->xres_virtual < var->xres)
++ var->xres_virtual = var->xres;
++
++ /* Default Y virtual size is 3*yres */
++ if (var->yres_virtual < var->yres * 3)
++ var->yres_virtual = var->yres * 3;
++
++ if ((var->bits_per_pixel != 32) && (var->bits_per_pixel != 24) &&
++ (var->bits_per_pixel != 16) && (var->bits_per_pixel != 12) &&
++ (var->bits_per_pixel != 8))
++ var->bits_per_pixel = 16;
++
++ switch (var->bits_per_pixel) {
++ case 8:
++ var->red.length = 3;
++ var->red.offset = 5;
++ var->red.msb_right = 0;
++
++ var->green.length = 3;
++ var->green.offset = 2;
++ var->green.msb_right = 0;
++
++ var->blue.length = 2;
++ var->blue.offset = 0;
++ var->blue.msb_right = 0;
++
++ var->transp.length = 0;
++ var->transp.offset = 0;
++ var->transp.msb_right = 0;
++ break;
++ case 16:
++ var->red.length = 5;
++ var->red.offset = 11;
++ var->red.msb_right = 0;
++
++ var->green.length = 6;
++ var->green.offset = 5;
++ var->green.msb_right = 0;
++
++ var->blue.length = 5;
++ var->blue.offset = 0;
++ var->blue.msb_right = 0;
++
++ var->transp.length = 0;
++ var->transp.offset = 0;
++ var->transp.msb_right = 0;
++ break;
++ case 24:
++ var->red.length = 8;
++ var->red.offset = 16;
++ var->red.msb_right = 0;
++
++ var->green.length = 8;
++ var->green.offset = 8;
++ var->green.msb_right = 0;
++
++ var->blue.length = 8;
++ var->blue.offset = 0;
++ var->blue.msb_right = 0;
++
++ var->transp.length = 0;
++ var->transp.offset = 0;
++ var->transp.msb_right = 0;
++ break;
++ case 32:
++ var->red.length = 8;
++ var->red.offset = 16;
++ var->red.msb_right = 0;
++
++ var->green.length = 8;
++ var->green.offset = 8;
++ var->green.msb_right = 0;
++
++ var->blue.length = 8;
++ var->blue.offset = 0;
++ var->blue.msb_right = 0;
++
++ var->transp.length = 8;
++ var->transp.offset = 24;
++ var->transp.msb_right = 0;
++ break;
++ }
++
++ if (var->pixclock < 1000) {
++ htotal = var->xres + var->right_margin + var->hsync_len +
++ var->left_margin;
++ vtotal = var->yres + var->lower_margin + var->vsync_len +
++ var->upper_margin;
++ var->pixclock = (vtotal * htotal * 6UL) / 100UL;
++ var->pixclock = KHZ2PICOS(var->pixclock);
++ dev_dbg(info->device,
++ "pixclock set for 60Hz refresh = %u ps\n",
++ var->pixclock);
++ }
++
++ var->height = -1;
++ var->width = -1;
++ var->grayscale = 0;
++
++ return 0;
++}
++
++static inline u_int _chan_to_field(u_int chan, struct fb_bitfield *bf)
++{
++ chan &= 0xffff;
++ chan >>= 16 - bf->length;
++ return chan << bf->offset;
++}
++
++static int mxcfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
++ u_int trans, struct fb_info *fbi)
++{
++ unsigned int val;
++ int ret = 1;
++
++ /*
++ * If greyscale is true, then we convert the RGB value
++ * to greyscale no matter what visual we are using.
++ */
++ if (fbi->var.grayscale)
++ red = green = blue = (19595 * red + 38470 * green +
++ 7471 * blue) >> 16;
++ switch (fbi->fix.visual) {
++ case FB_VISUAL_TRUECOLOR:
++ /*
++ * 16-bit True Colour. We encode the RGB value
++ * according to the RGB bitfield information.
++ */
++ if (regno < 16) {
++ u32 *pal = fbi->pseudo_palette;
++
++ val = _chan_to_field(red, &fbi->var.red);
++ val |= _chan_to_field(green, &fbi->var.green);
++ val |= _chan_to_field(blue, &fbi->var.blue);
++
++ pal[regno] = val;
++ ret = 0;
++ }
++ break;
++
++ case FB_VISUAL_STATIC_PSEUDOCOLOR:
++ case FB_VISUAL_PSEUDOCOLOR:
++ break;
++ }
++
++ return ret;
++}
++
++/*
++ * Function to handle custom ioctls for MXC framebuffer.
++ *
++ * @param inode inode struct
++ *
++ * @param file file struct
++ *
++ * @param cmd Ioctl command to handle
++ *
++ * @param arg User pointer to command arguments
++ *
++ * @param fbi framebuffer information pointer
++ */
++static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
++{
++ int retval = 0;
++ int __user *argp = (void __user *)arg;
++ struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
++
++ switch (cmd) {
++ case MXCFB_SET_GBL_ALPHA:
++ {
++ struct mxcfb_gbl_alpha ga;
++
++ if (copy_from_user(&ga, (void *)arg, sizeof(ga))) {
++ retval = -EFAULT;
++ break;
++ }
++
++ if (ipu_disp_set_global_alpha(mxc_fbi->ipu_ch,
++ (bool)ga.enable,
++ ga.alpha)) {
++ retval = -EINVAL;
++ break;
++ }
++
++ if (ga.enable)
++ mxc_fbi->alpha_chan_en = false;
++
++ if (ga.enable)
++ dev_dbg(fbi->device,
++ "Set global alpha of %s to %d\n",
++ fbi->fix.id, ga.alpha);
++ break;
++ }
++ case MXCFB_SET_LOC_ALPHA:
++ {
++ struct mxcfb_loc_alpha la;
++ int i;
++ char *video_plane_idstr = "";
++
++ if (copy_from_user(&la, (void *)arg, sizeof(la))) {
++ retval = -EFAULT;
++ break;
++ }
++
++ if (ipu_disp_set_global_alpha(mxc_fbi->ipu_ch,
++ !(bool)la.enable, 0)) {
++ retval = -EINVAL;
++ break;
++ }
++
++ if (la.enable && !la.alpha_in_pixel) {
++ mxc_fbi->alpha_chan_en = true;
++
++ if (mxc_fbi->ipu_ch == MEM_FG_SYNC)
++ video_plane_idstr = "DISP3 BG";
++ else if (mxc_fbi->ipu_ch == MEM_BG_SYNC)
++ video_plane_idstr = "DISP3 FG";
++
++ for (i = 0; i < num_registered_fb; i++) {
++ char *idstr = registered_fb[i]->fix.id;
++ if (strcmp(idstr, video_plane_idstr) == 0) {
++ ((struct mxcfb_info *)(registered_fb[i]->par))->alpha_chan_en = false;
++ break;
++ }
++ }
++ } else
++ mxc_fbi->alpha_chan_en = false;
++
++ console_lock();
++ mxcfb_set_par(fbi);
++ console_unlock();
++
++ la.alpha_phy_addr0 = mxc_fbi->alpha_phy_addr0;
++ la.alpha_phy_addr1 = mxc_fbi->alpha_phy_addr1;
++ if (copy_to_user((void *)arg, &la, sizeof(la))) {
++ retval = -EFAULT;
++ break;
++ }
++
++ if (la.enable)
++ dev_dbg(fbi->device,
++ "Enable DP local alpha for %s\n",
++ fbi->fix.id);
++ break;
++ }
++ case MXCFB_SET_LOC_ALP_BUF:
++ {
++ unsigned long base;
++ uint32_t ipu_alp_ch_irq;
++
++ if (!(((mxc_fbi->ipu_ch == MEM_FG_SYNC) ||
++ (mxc_fbi->ipu_ch == MEM_BG_SYNC)) &&
++ (mxc_fbi->alpha_chan_en))) {
++ dev_err(fbi->device,
++ "Should use background or overlay "
++ "framebuffer to set the alpha buffer "
++ "number\n");
++ return -EINVAL;
++ }
++
++ if (get_user(base, argp))
++ return -EFAULT;
++
++ if (base != mxc_fbi->alpha_phy_addr0 &&
++ base != mxc_fbi->alpha_phy_addr1) {
++ dev_err(fbi->device,
++ "Wrong alpha buffer physical address "
++ "%lu\n", base);
++ return -EINVAL;
++ }
++
++ if (mxc_fbi->ipu_ch == MEM_FG_SYNC)
++ ipu_alp_ch_irq = IPU_IRQ_FG_ALPHA_SYNC_EOF;
++ else
++ ipu_alp_ch_irq = IPU_IRQ_BG_ALPHA_SYNC_EOF;
++
++ down(&mxc_fbi->alpha_flip_sem);
++
++ mxc_fbi->cur_ipu_alpha_buf =
++ !mxc_fbi->cur_ipu_alpha_buf;
++ if (ipu_update_channel_buffer(mxc_fbi->ipu_ch,
++ IPU_ALPHA_IN_BUFFER,
++ mxc_fbi->
++ cur_ipu_alpha_buf,
++ base) == 0) {
++ ipu_select_buffer(mxc_fbi->ipu_ch,
++ IPU_ALPHA_IN_BUFFER,
++ mxc_fbi->cur_ipu_alpha_buf);
++ ipu_clear_irq(ipu_alp_ch_irq);
++ ipu_enable_irq(ipu_alp_ch_irq);
++ } else {
++ dev_err(fbi->device,
++ "Error updating %s SDC alpha buf %d "
++ "to address=0x%08lX\n",
++ fbi->fix.id,
++ mxc_fbi->cur_ipu_alpha_buf, base);
++ }
++ break;
++ }
++ case MXCFB_SET_CLR_KEY:
++ {
++ struct mxcfb_color_key key;
++ if (copy_from_user(&key, (void *)arg, sizeof(key))) {
++ retval = -EFAULT;
++ break;
++ }
++ retval = ipu_disp_set_color_key(mxc_fbi->ipu_ch,
++ key.enable,
++ key.color_key);
++ dev_dbg(fbi->device, "Set color key to 0x%08X\n",
++ key.color_key);
++ break;
++ }
++ case MXCFB_SET_GAMMA:
++ {
++ struct mxcfb_gamma gamma;
++ if (copy_from_user(&gamma, (void *)arg, sizeof(gamma))) {
++ retval = -EFAULT;
++ break;
++ }
++ retval = ipu_disp_set_gamma_correction(mxc_fbi->ipu_ch,
++ gamma.enable,
++ gamma.constk,
++ gamma.slopek);
++ break;
++ }
++ case MXCFB_WAIT_FOR_VSYNC:
++ {
++ if (mxc_fbi->ipu_ch == MEM_FG_SYNC) {
++ struct mxcfb_info *bg_mxcfbi = NULL;
++ int i;
++ for (i = 0; i < num_registered_fb; i++) {
++ bg_mxcfbi =
++ ((struct mxcfb_info *)(registered_fb[i]->par));
++
++ if (bg_mxcfbi->ipu_ch == MEM_BG_SYNC)
++ break;
++ }
++ if (bg_mxcfbi->cur_blank != FB_BLANK_UNBLANK) {
++ retval = -EINVAL;
++ break;
++ }
++ }
++ if (mxc_fbi->cur_blank != FB_BLANK_UNBLANK) {
++ retval = -EINVAL;
++ break;
++ }
++
++ init_completion(&mxc_fbi->vsync_complete);
++
++ ipu_clear_irq(mxc_fbi->ipu_ch_irq);
++ mxc_fbi->wait4vsync = 1;
++ ipu_enable_irq(mxc_fbi->ipu_ch_irq);
++ retval = wait_for_completion_interruptible_timeout(
++ &mxc_fbi->vsync_complete, 1 * HZ);
++ if (retval == 0) {
++ dev_err(fbi->device,
++ "MXCFB_WAIT_FOR_VSYNC: timeout %d\n",
++ retval);
++ mxc_fbi->wait4vsync = 0;
++ retval = -ETIME;
++ } else if (retval > 0) {
++ retval = 0;
++ }
++ break;
++ }
++ case FBIO_ALLOC:
++ {
++ int size;
++ struct mxcfb_alloc_list *mem;
++
++ mem = kzalloc(sizeof(*mem), GFP_KERNEL);
++ if (mem == NULL)
++ return -ENOMEM;
++
++ if (get_user(size, argp))
++ return -EFAULT;
++
++ mem->size = PAGE_ALIGN(size);
++
++ mem->cpu_addr = dma_alloc_coherent(fbi->device, size,
++ &mem->phy_addr,
++ GFP_DMA);
++ if (mem->cpu_addr == NULL) {
++ kfree(mem);
++ return -ENOMEM;
++ }
++
++ list_add(&mem->list, &fb_alloc_list);
++
++ dev_dbg(fbi->device, "allocated %d bytes @ 0x%08X\n",
++ mem->size, mem->phy_addr);
++
++ if (put_user(mem->phy_addr, argp))
++ return -EFAULT;
++
++ break;
++ }
++ case FBIO_FREE:
++ {
++ unsigned long offset;
++ struct mxcfb_alloc_list *mem;
++
++ if (get_user(offset, argp))
++ return -EFAULT;
++
++ retval = -EINVAL;
++ list_for_each_entry(mem, &fb_alloc_list, list) {
++ if (mem->phy_addr == offset) {
++ list_del(&mem->list);
++ dma_free_coherent(fbi->device,
++ mem->size,
++ mem->cpu_addr,
++ mem->phy_addr);
++ kfree(mem);
++ retval = 0;
++ break;
++ }
++ }
++
++ break;
++ }
++ case MXCFB_SET_OVERLAY_POS:
++ {
++ struct mxcfb_pos pos;
++ struct fb_info *bg_fbi = NULL;
++ struct mxcfb_info *bg_mxcfbi = NULL;
++ int i;
++
++ if (mxc_fbi->ipu_ch != MEM_FG_SYNC) {
++ dev_err(fbi->device, "Should use the overlay "
++ "framebuffer to set the position of "
++ "the overlay window\n");
++ retval = -EINVAL;
++ break;
++ }
++
++ if (copy_from_user(&pos, (void *)arg, sizeof(pos))) {
++ retval = -EFAULT;
++ break;
++ }
++
++ for (i = 0; i < num_registered_fb; i++) {
++ bg_mxcfbi =
++ ((struct mxcfb_info *)(registered_fb[i]->par));
++
++ if (bg_mxcfbi->ipu_ch == MEM_BG_SYNC) {
++ bg_fbi = registered_fb[i];
++ break;
++ }
++ }
++
++ if (bg_fbi == NULL) {
++ dev_err(fbi->device, "Cannot find the "
++ "background framebuffer\n");
++ retval = -ENOENT;
++ break;
++ }
++
++ if (fbi->var.xres + pos.x > bg_fbi->var.xres) {
++ if (bg_fbi->var.xres < fbi->var.xres)
++ pos.x = 0;
++ else
++ pos.x = bg_fbi->var.xres - fbi->var.xres;
++ }
++ if (fbi->var.yres + pos.y > bg_fbi->var.yres) {
++ if (bg_fbi->var.yres < fbi->var.yres)
++ pos.y = 0;
++ else
++ pos.y = bg_fbi->var.yres - fbi->var.yres;
++ }
++
++ retval = ipu_disp_set_window_pos(mxc_fbi->ipu_ch,
++ pos.x, pos.y);
++
++ if (copy_to_user((void *)arg, &pos, sizeof(pos))) {
++ retval = -EFAULT;
++ break;
++ }
++ break;
++ }
++ case MXCFB_GET_FB_IPU_CHAN:
++ {
++ struct mxcfb_info *mxc_fbi =
++ (struct mxcfb_info *)fbi->par;
++
++ if (put_user(mxc_fbi->ipu_ch, argp))
++ return -EFAULT;
++ break;
++ }
++ case MXCFB_GET_DIFMT:
++ {
++ struct mxcfb_info *mxc_fbi =
++ (struct mxcfb_info *)fbi->par;
++
++ if (put_user(mxc_fbi->ipu_di_pix_fmt, argp))
++ return -EFAULT;
++ break;
++ }
++ case MXCFB_GET_FB_IPU_DI:
++ {
++ struct mxcfb_info *mxc_fbi =
++ (struct mxcfb_info *)fbi->par;
++
++ if (put_user(mxc_fbi->ipu_di, argp))
++ return -EFAULT;
++ break;
++ }
++ case MXCFB_GET_FB_BLANK:
++ {
++ struct mxcfb_info *mxc_fbi =
++ (struct mxcfb_info *)fbi->par;
++
++ if (put_user(mxc_fbi->cur_blank, argp))
++ return -EFAULT;
++ break;
++ }
++ case MXCFB_SET_DIFMT:
++ {
++ struct mxcfb_info *mxc_fbi =
++ (struct mxcfb_info *)fbi->par;
++
++ if (get_user(mxc_fbi->ipu_di_pix_fmt, argp))
++ return -EFAULT;
++
++ break;
++ }
++ default:
++ retval = -EINVAL;
++ }
++ return retval;
++}
++
++/*
++ * mxcfb_blank():
++ * Blank the display.
++ */
++static int mxcfb_blank(int blank, struct fb_info *info)
++{
++ struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)info->par;
++
++ dev_dbg(info->device, "blank = %d\n", blank);
++
++ if (mxc_fbi->cur_blank == blank)
++ return 0;
++
++ mxc_fbi->next_blank = blank;
++
++ switch (blank) {
++ case FB_BLANK_POWERDOWN:
++ case FB_BLANK_VSYNC_SUSPEND:
++ case FB_BLANK_HSYNC_SUSPEND:
++ case FB_BLANK_NORMAL:
++ ipu_disable_channel(mxc_fbi->ipu_ch, true);
++ ipu_uninit_sync_panel(mxc_fbi->ipu_di);
++ ipu_uninit_channel(mxc_fbi->ipu_ch);
++ break;
++ case FB_BLANK_UNBLANK:
++ mxcfb_set_par(info);
++ break;
++ }
++ mxc_fbi->cur_blank = blank;
++ return 0;
++}
++
++/*
++ * Pan or Wrap the Display
++ *
++ * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
++ *
++ * @param var Variable screen buffer information
++ * @param info Framebuffer information pointer
++ */
++static int
++mxcfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
++{
++ struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)info->par,
++ *mxc_graphic_fbi = NULL;
++ u_int y_bottom;
++ unsigned long base, active_alpha_phy_addr = 0;
++ bool loc_alpha_en = false;
++ int i = 0;
++
++ if (info->var.yoffset == var->yoffset)
++ return 0; /* No change, do nothing */
++
++ /* no pan display during fb blank */
++ if (mxc_fbi->ipu_ch == MEM_FG_SYNC) {
++ struct mxcfb_info *bg_mxcfbi = NULL;
++ int j;
++ for (j = 0; j < num_registered_fb; j++) {
++ bg_mxcfbi =
++ ((struct mxcfb_info *)(registered_fb[j]->par));
++
++ if (bg_mxcfbi->ipu_ch == MEM_BG_SYNC)
++ break;
++ }
++ if (bg_mxcfbi->cur_blank != FB_BLANK_UNBLANK)
++ return -EINVAL;
++ }
++ if (mxc_fbi->cur_blank != FB_BLANK_UNBLANK)
++ return -EINVAL;
++
++ y_bottom = var->yoffset;
++
++ if (!(var->vmode & FB_VMODE_YWRAP))
++ y_bottom += var->yres;
++
++ if (y_bottom > info->var.yres_virtual)
++ return -EINVAL;
++
++ base = (var->yoffset * var->xres_virtual + var->xoffset);
++ base = (var->bits_per_pixel) * base / 8;
++ base += info->fix.smem_start;
++
++ /* Check if DP local alpha is enabled and find the graphic fb */
++ if (mxc_fbi->ipu_ch == MEM_BG_SYNC || mxc_fbi->ipu_ch == MEM_FG_SYNC) {
++ for (i = 0; i < num_registered_fb; i++) {
++ char *idstr = registered_fb[i]->fix.id;
++ if ((strcmp(idstr, "DISP3 BG") == 0 ||
++ strcmp(idstr, "DISP3 FG") == 0) &&
++ ((struct mxcfb_info *)
++ (registered_fb[i]->par))->alpha_chan_en) {
++ loc_alpha_en = true;
++ mxc_graphic_fbi = (struct mxcfb_info *)
++ (registered_fb[i]->par);
++ active_alpha_phy_addr =
++ mxc_fbi->cur_ipu_alpha_buf ?
++ mxc_graphic_fbi->alpha_phy_addr1 :
++ mxc_graphic_fbi->alpha_phy_addr0;
++ dev_dbg(info->device, "Updating SDC alpha "
++ "buf %d address=0x%08lX\n",
++ !mxc_fbi->cur_ipu_alpha_buf,
++ active_alpha_phy_addr);
++ break;
++ }
++ }
++ }
++
++ down(&mxc_fbi->flip_sem);
++
++ mxc_fbi->cur_ipu_buf = (++mxc_fbi->cur_ipu_buf) % 3;
++ mxc_fbi->cur_ipu_alpha_buf = !mxc_fbi->cur_ipu_alpha_buf;
++
++ dev_dbg(info->device, "Updating SDC %s buf %d address=0x%08lX\n",
++ info->fix.id, mxc_fbi->cur_ipu_buf, base);
++
++ if (ipu_update_channel_buffer(mxc_fbi->ipu_ch, IPU_INPUT_BUFFER,
++ mxc_fbi->cur_ipu_buf, base) == 0) {
++ /* Update the DP local alpha buffer only for graphic plane */
++ if (loc_alpha_en && mxc_graphic_fbi == mxc_fbi &&
++ ipu_update_channel_buffer(mxc_graphic_fbi->ipu_ch,
++ IPU_ALPHA_IN_BUFFER,
++ mxc_fbi->cur_ipu_alpha_buf,
++ active_alpha_phy_addr) == 0) {
++ ipu_select_buffer(mxc_graphic_fbi->ipu_ch,
++ IPU_ALPHA_IN_BUFFER,
++ mxc_fbi->cur_ipu_alpha_buf);
++ }
++
++ ipu_select_buffer(mxc_fbi->ipu_ch, IPU_INPUT_BUFFER,
++ mxc_fbi->cur_ipu_buf);
++ ipu_clear_irq(mxc_fbi->ipu_ch_irq);
++ ipu_enable_irq(mxc_fbi->ipu_ch_irq);
++ } else {
++ dev_err(info->device,
++ "Error updating SDC buf %d to address=0x%08lX, "
++ "current buf %d, buf0 ready %d, buf1 ready %d, "
++ "buf2 ready %d\n", mxc_fbi->cur_ipu_buf, base,
++ ipu_get_cur_buffer_idx(mxc_fbi->ipu_ch,
++ IPU_INPUT_BUFFER),
++ ipu_check_buffer_ready(mxc_fbi->ipu_ch,
++ IPU_INPUT_BUFFER, 0),
++ ipu_check_buffer_ready(mxc_fbi->ipu_ch,
++ IPU_INPUT_BUFFER, 1),
++ ipu_check_buffer_ready(mxc_fbi->ipu_ch,
++ IPU_INPUT_BUFFER, 2));
++ mxc_fbi->cur_ipu_buf = (++mxc_fbi->cur_ipu_buf) % 3;
++ mxc_fbi->cur_ipu_buf = (++mxc_fbi->cur_ipu_buf) % 3;
++ mxc_fbi->cur_ipu_alpha_buf = !mxc_fbi->cur_ipu_alpha_buf;
++ ipu_clear_irq(mxc_fbi->ipu_ch_irq);
++ ipu_enable_irq(mxc_fbi->ipu_ch_irq);
++ return -EBUSY;
++ }
++
++ dev_dbg(info->device, "Update complete\n");
++
++ info->var.yoffset = var->yoffset;
++
++ return 0;
++}
++
++/*
++ * Function to handle custom mmap for MXC framebuffer.
++ *
++ * @param fbi framebuffer information pointer
++ *
++ * @param vma Pointer to vm_area_struct
++ */
++static int mxcfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
++{
++ bool found = false;
++ u32 len;
++ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
++ struct mxcfb_alloc_list *mem;
++ struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
++
++ if (offset < fbi->fix.smem_len) {
++ /* mapping framebuffer memory */
++ len = fbi->fix.smem_len - offset;
++ vma->vm_pgoff = (fbi->fix.smem_start + offset) >> PAGE_SHIFT;
++ } else if ((vma->vm_pgoff ==
++ (mxc_fbi->alpha_phy_addr0 >> PAGE_SHIFT)) ||
++ (vma->vm_pgoff ==
++ (mxc_fbi->alpha_phy_addr1 >> PAGE_SHIFT))) {
++ len = mxc_fbi->alpha_mem_len;
++ } else {
++ list_for_each_entry(mem, &fb_alloc_list, list) {
++ if (offset == mem->phy_addr) {
++ found = true;
++ len = mem->size;
++ break;
++ }
++ }
++ if (!found)
++ return -EINVAL;
++ }
++
++ len = PAGE_ALIGN(len);
++ if (vma->vm_end - vma->vm_start > len)
++ return -EINVAL;
++
++ /* make buffers bufferable */
++ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
++
++ vma->vm_flags |= VM_IO | VM_RESERVED;
++
++ if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
++ vma->vm_end - vma->vm_start, vma->vm_page_prot)) {
++ dev_dbg(fbi->device, "mmap remap_pfn_range failed\n");
++ return -ENOBUFS;
++ }
++
++ return 0;
++}
++
++/*!
++ * This structure contains the pointers to the control functions that are
++ * invoked by the core framebuffer driver to perform operations like
++ * blitting, rectangle filling, copy regions and cursor definition.
++ */
++static struct fb_ops mxcfb_ops = {
++ .owner = THIS_MODULE,
++ .fb_set_par = mxcfb_set_par,
++ .fb_check_var = mxcfb_check_var,
++ .fb_setcolreg = mxcfb_setcolreg,
++ .fb_pan_display = mxcfb_pan_display,
++ .fb_ioctl = mxcfb_ioctl,
++ .fb_mmap = mxcfb_mmap,
++ .fb_fillrect = cfb_fillrect,
++ .fb_copyarea = cfb_copyarea,
++ .fb_imageblit = cfb_imageblit,
++ .fb_blank = mxcfb_blank,
++};
++
++static irqreturn_t mxcfb_irq_handler(int irq, void *dev_id)
++{
++ struct fb_info *fbi = dev_id;
++ struct mxcfb_info *mxc_fbi = fbi->par;
++
++ if (mxc_fbi->wait4vsync) {
++ complete(&mxc_fbi->vsync_complete);
++ ipu_disable_irq(irq);
++ mxc_fbi->wait4vsync = 0;
++ } else {
++ up(&mxc_fbi->flip_sem);
++ ipu_disable_irq(irq);
++ }
++ return IRQ_HANDLED;
++}
++
++static irqreturn_t mxcfb_alpha_irq_handler(int irq, void *dev_id)
++{
++ struct fb_info *fbi = dev_id;
++ struct mxcfb_info *mxc_fbi = fbi->par;
++
++ up(&mxc_fbi->alpha_flip_sem);
++ ipu_disable_irq(irq);
++ return IRQ_HANDLED;
++}
++
++/*
++ * Suspends the framebuffer and blanks the screen. Power management support
++ */
++static int mxcfb_suspend(struct platform_device *pdev, pm_message_t state)
++{
++ struct fb_info *fbi = platform_get_drvdata(pdev);
++ struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
++ int saved_blank;
++
++ console_lock();
++ fb_set_suspend(fbi, 1);
++ saved_blank = mxc_fbi->cur_blank;
++ mxcfb_blank(FB_BLANK_POWERDOWN, fbi);
++ mxc_fbi->next_blank = saved_blank;
++ mxc_fbi->fb_suspended = true;
++ console_unlock();
++
++ return 0;
++}
++
++/*
++ * Resumes the framebuffer and unblanks the screen. Power management support
++ */
++static int mxcfb_resume(struct platform_device *pdev)
++{
++ struct fb_info *fbi = platform_get_drvdata(pdev);
++ struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
++
++ console_lock();
++ mxc_fbi->fb_suspended = false;
++ mxcfb_blank(mxc_fbi->next_blank, fbi);
++ fb_set_suspend(fbi, 0);
++ console_unlock();
++
++ return 0;
++}
++
++/*
++ * Main framebuffer functions
++ */
++
++/*!
++ * Allocates the DRAM memory for the frame buffer. This buffer is remapped
++ * into a non-cached, non-buffered, memory region to allow palette and pixel
++ * writes to occur without flushing the cache. Once this area is remapped,
++ * all virtual memory access to the video memory should occur at the new region.
++ *
++ * @param fbi framebuffer information pointer
++ *
++ * @return Error code indicating success or failure
++ */
++static int mxcfb_map_video_memory(struct fb_info *fbi)
++{
++ if (fbi->fix.smem_len < fbi->var.yres_virtual * fbi->fix.line_length)
++ fbi->fix.smem_len = fbi->var.yres_virtual *
++ fbi->fix.line_length;
++
++ fbi->screen_base = dma_alloc_writecombine(fbi->device,
++ fbi->fix.smem_len,
++ (dma_addr_t *)&fbi->fix.smem_start,
++ GFP_DMA);
++ if (fbi->screen_base == 0) {
++ dev_err(fbi->device, "Unable to allocate framebuffer memory\n");
++ fbi->fix.smem_len = 0;
++ fbi->fix.smem_start = 0;
++ return -EBUSY;
++ }
++
++ dev_dbg(fbi->device, "allocated fb @ paddr=0x%08X, size=%d.\n",
++ (uint32_t) fbi->fix.smem_start, fbi->fix.smem_len);
++
++ fbi->screen_size = fbi->fix.smem_len;
++
++ /* Clear the screen */
++ memset((char *)fbi->screen_base, 0, fbi->fix.smem_len);
++
++ return 0;
++}
++
++/*!
++ * De-allocates the DRAM memory for the frame buffer.
++ *
++ * @param fbi framebuffer information pointer
++ *
++ * @return Error code indicating success or failure
++ */
++static int mxcfb_unmap_video_memory(struct fb_info *fbi)
++{
++ dma_free_writecombine(fbi->device, fbi->fix.smem_len,
++ fbi->screen_base, fbi->fix.smem_start);
++ fbi->screen_base = 0;
++ fbi->fix.smem_start = 0;
++ fbi->fix.smem_len = 0;
++ return 0;
++}
++
++/*!
++ * Initializes the framebuffer information pointer. After allocating
++ * sufficient memory for the framebuffer structure, the fields are
++ * filled with custom information passed in from the configurable
++ * structures. This includes information such as bits per pixel,
++ * color maps, screen width/height and RGBA offsets.
++ *
++ * @return Framebuffer structure initialized with our information
++ */
++static struct fb_info *mxcfb_init_fbinfo(struct device *dev, struct fb_ops *ops)
++{
++ struct fb_info *fbi;
++ struct mxcfb_info *mxcfbi;
++
++ /*
++ * Allocate sufficient memory for the fb structure
++ */
++ fbi = framebuffer_alloc(sizeof(struct mxcfb_info), dev);
++ if (!fbi)
++ return NULL;
++
++ mxcfbi = (struct mxcfb_info *)fbi->par;
++
++ fbi->var.activate = FB_ACTIVATE_NOW;
++
++ fbi->fbops = ops;
++ fbi->flags = FBINFO_FLAG_DEFAULT;
++ fbi->pseudo_palette = mxcfbi->pseudo_palette;
++
++ /*
++ * Allocate colormap
++ */
++ fb_alloc_cmap(&fbi->cmap, 16, 0);
++
++ return fbi;
++}
++
++static ssize_t show_disp_chan(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct fb_info *info = dev_get_drvdata(dev);
++ struct mxcfb_info *mxcfbi = (struct mxcfb_info *)info->par;
++
++ if (mxcfbi->ipu_ch == MEM_BG_SYNC)
++ return sprintf(buf, "2-layer-fb-bg\n");
++ else if (mxcfbi->ipu_ch == MEM_FG_SYNC)
++ return sprintf(buf, "2-layer-fb-fg\n");
++ else if (mxcfbi->ipu_ch == MEM_DC_SYNC)
++ return sprintf(buf, "1-layer-fb\n");
++ else
++ return sprintf(buf, "err: no display chan\n");
++}
++
++static ssize_t swap_disp_chan(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct fb_info *info = dev_get_drvdata(dev);
++ struct mxcfb_info *mxcfbi = (struct mxcfb_info *)info->par;
++ struct mxcfb_info *fg_mxcfbi = NULL;
++
++ console_lock();
++ /* swap only happen between DP-BG and DC, while DP-FG disable */
++ if (((mxcfbi->ipu_ch == MEM_BG_SYNC) &&
++ (strstr(buf, "1-layer-fb") != NULL)) ||
++ ((mxcfbi->ipu_ch == MEM_DC_SYNC) &&
++ (strstr(buf, "2-layer-fb-bg") != NULL))) {
++ int i;
++
++ for (i = 0; i < num_registered_fb; i++) {
++ fg_mxcfbi =
++ (struct mxcfb_info *)mxcfb_info[i]->par;
++ if (fg_mxcfbi->ipu_ch == MEM_FG_SYNC)
++ break;
++ else
++ fg_mxcfbi = NULL;
++ }
++ ...
[truncated message content] |