add fb
author钟勇汪 <zyw@rock-chips.com>
Fri, 14 May 2010 12:44:56 +0000 (12:44 +0000)
committer黄涛 <huangtao@rock-chips.com>
Mon, 21 Jun 2010 05:34:54 +0000 (13:34 +0800)
arch/arm/mach-rk2818/board-midsdk.c
arch/arm/mach-rk2818/devices.c
arch/arm/mach-rk2818/devices.h
arch/arm/mach-rk2818/include/mach/board.h
drivers/video/Kconfig
drivers/video/Makefile
drivers/video/display/Kconfig
drivers/video/display/Makefile
drivers/video/rk2818_fb.c [new file with mode: 0644]
drivers/video/rk2818_fb.h [new file with mode: 0644]

index 851770d25d690b4bfd2c9f15c25d3c8e3704b469..07d127be01a527fcd06994a07a60b271eaced5dd 100644 (file)
@@ -245,6 +245,28 @@ static struct spi_board_info board_spi_devices[] = {
        },
 
 }; 
+/*rk2818_fb gpio information*/
+static struct rk2818_fb_gpio rk2818_fb_gpio_info = {
+    .lcd_cs     = 0,
+    .display_on = (GPIO_LOW<<16)|RK2818_PIN_PA2,
+    .lcd_standby = 0,
+    .mcu_fmk_pin = 0,
+};
+
+/*rk2818_fb iomux information*/
+static struct rk2818_fb_iomux rk2818_fb_iomux_info = {
+    .data16     = GPIOC_LCDC16BIT_SEL_NAME,
+    .data18     = GPIOC_LCDC18BIT_SEL_NAME,
+    .data24     = GPIOC_LCDC24BIT_SEL_NAME,
+    .den        = CXGPIO_LCDDEN_SEL_NAME,
+    .vsync      = CXGPIO_LCDVSYNC_SEL_NAME,
+    .mcu_fmk    = 0,
+};
+/*rk2818_fb*/
+struct rk2818_fb_mach_info rk2818_fb_mach_info = {
+    .gpio = &rk2818_fb_gpio_info,
+    .iomux = &rk2818_fb_iomux_info,
+};
 
 static struct platform_device *devices[] __initdata = {
        &rk2818_device_uart1,
@@ -256,6 +278,7 @@ static struct platform_device *devices[] __initdata = {
        &rk2818_device_i2c1,
 #endif
        &rk2818_device_spim,
+    &rk2818_device_fb,    
 };
 
 extern struct sys_timer rk2818_timer;
index 8b27b4c5ccdea384578a0ca73cfd64a261873ef6..65d1ed19279b56625ff66ec78d9c624f7501e6e6 100644 (file)
@@ -168,6 +168,32 @@ struct platform_device rk2818_device_spim = {
        .resource       = resources_spim,
 };
 
+/* rk2818 fb resource */
+static struct resource rk2818_fb_resource[] = {
+       [0] = {
+               .start = RK2818_LCDC_PHYS,
+               .end   = RK2818_LCDC_PHYS + RK2818_LCDC_SIZE - 1,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = IRQ_NR_LCDC,
+               .end   = IRQ_NR_LCDC,
+               .flags = IORESOURCE_IRQ,
+       },      
+};
+
+/*platform_device*/
+extern struct rk2818_fb_mach_info rk2818_fb_mach_info;
+
+struct platform_device rk2818_device_fb = {
+       .name             = "rk2818-fb",
+       .id               = 4,
+       .num_resources    = ARRAY_SIZE(rk2818_fb_resource),
+       .resource         = rk2818_fb_resource,
+       .dev            = {
+               .platform_data  = &rk2818_fb_mach_info,
+       }
+};
 //net device
 /* DM9000 */
 static struct resource dm9k_resource[] = {
index b3cc29876210bb3adb232c2dc4a8645a37f84586..505fdff65bce535f30bb05f7b1c30be20bc7ad7e 100644 (file)
@@ -26,5 +26,5 @@ extern struct platform_device rk2818_device_i2c1;
 extern struct rk2818_i2c_platform_data default_i2c0_data;
 extern struct rk2818_i2c_platform_data default_i2c1_data;
 extern struct platform_device rk2818_device_dm9k;
-
+extern struct platform_device rk2818_device_fb;
 #endif
index f013efb7256135c88c4653ac2a9011e7666d82cb..244280e7f56cbe188942f29882804cbb78454d79 100644 (file)
@@ -35,6 +35,27 @@ struct rk2818_i2c_platform_data {
        void    (*cfg_gpio)(struct platform_device *dev);
 };
 
+struct rk2818_fb_gpio{
+    u32 display_on;
+    u32 lcd_cs;
+    u32 lcd_standby;
+    u32 mcu_fmk_pin;
+};
+
+struct rk2818_fb_iomux{
+    char *data16;
+    char *data18;
+    char *data24;
+    char *den;
+    char *vsync;
+    char *mcu_fmk;
+};
+
+struct rk2818_fb_mach_info {
+    struct rk2818_fb_gpio *gpio;
+    struct rk2818_fb_iomux *iomux;
+};
+
 /* common init routines for use by arch/arm/mach-msm/board-*.c */
 void __init rk2818_add_devices(void);
 void __init rk2818_map_common_io(void);
index 188e1ba3b69ff538b778ec84366ed63ff69d9fbe..b2837066ee0d0fb3881dd0c35faa96fc9eecf65a 100644 (file)
@@ -1927,6 +1927,15 @@ config FB_S3C2410_DEBUG
          Turn on debugging messages. Note that you can set/unset at run time
          through sysfs
 
+config FB_RK2818
+       tristate "RK2818 lcd control"
+       depends on FB
+       select FB_CFB_FILLRECT
+       select FB_CFB_COPYAREA
+       select FB_CFB_IMAGEBLIT
+       ---help---
+         Framebuffer driver for RK2818 Platform,select it if you using rk2818
+         
 config FB_SM501
        tristate "Silicon Motion SM501 framebuffer support"
        depends on FB && MFD_SM501
index 80232e124889b1eab9b26f4869c3a1a010aaade4..6777b5a36243c8e601f881908820094486172780 100644 (file)
@@ -120,6 +120,7 @@ obj-$(CONFIG_FB_PNX4008_DUM)          += pnx4008/
 obj-$(CONFIG_FB_PNX4008_DUM_RGB)  += pnx4008/
 obj-$(CONFIG_FB_IBM_GXT4500)     += gxt4500.o
 obj-$(CONFIG_FB_PS3)             += ps3fb.o
+obj-$(CONFIG_FB_RK2818)       += rk2818_fb.o
 obj-$(CONFIG_FB_SM501)            += sm501fb.o
 obj-$(CONFIG_FB_XILINX)           += xilinxfb.o
 obj-$(CONFIG_FB_SH_MOBILE_LCDC)          += sh_mobile_lcdcfb.o
index f99af931d4f8a72f7e32b8fc06d88ed4bad1889e..19e534aca13b9a99fdfc554f27640e70c61fe668 100644 (file)
@@ -20,5 +20,6 @@ config DISPLAY_SUPPORT
 
 comment "Display hardware drivers"
        depends on DISPLAY_SUPPORT
+source "drivers/video/display/screen/Kconfig"
 
 endmenu
index c0ea832bf171073acea9b89d437d30c651234df1..c7d6d8b6b6962d44e2e320b7b86560c84a76613f 100644 (file)
@@ -3,4 +3,4 @@
 display-objs                           := display-sysfs.o
 
 obj-$(CONFIG_DISPLAY_SUPPORT)          += display.o
-
+obj-$(CONFIG_DISPLAY_SUPPORT)      += screen/
diff --git a/drivers/video/rk2818_fb.c b/drivers/video/rk2818_fb.c
new file mode 100644 (file)
index 0000000..324484e
--- /dev/null
@@ -0,0 +1,2449 @@
+/*
+ * drivers/video/rk2818_fb.c 
+ *
+ * Copyright (C) 2010 ROCKCHIP, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/backlight.h>
+#include <linux/timer.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+
+
+#include <asm/io.h>
+#include <asm/div64.h>
+#include <asm/uaccess.h>
+
+#include "rk2818_fb.h"
+
+#ifdef CONFIG_PM
+#include <linux/pm.h>
+#endif
+
+#include <mach/iomux.h>
+#include <mach/gpio.h>
+#include <mach/board.h>
+#include <mach/rk2818_iomap.h>
+//#include <asm/uaccess.h>
+
+#ifdef CONFIG_ANDROID_POWER
+#include <linux/android_power.h>
+#endif
+
+#include "./display/screen/screen.h"
+
+
+#define FMK_USE_HARDTIMER       1       //frame mark use hard timer replace high timer
+#define WIN1_USE_DOUBLE_BUF     1       //win1 use double buf to accelerate display
+#define LANDSCAPE_USE_ROTATE    1       //rotate win1 in landscape with mcu panel
+
+#if 1
+       #define fbprintk(msg...)        printk(msg);
+#else
+       #define fbprintk(msg...)
+#endif
+
+
+#if 1
+       #define fbprintk2(msg...)       printk(msg);
+#else
+       #define fbprintk2(msg...)
+#endif
+/*
+#define LcdReadBit(inf, addr, msk)      ((inf->regbak.addr=__raw_readl(inf->preg->addr))&(msk))
+#define LcdWrReg(inf, addr, val)         __raw_writel(val, inf->regbak.addr); inf->preg->addr = (val)                                         
+#define LcdRdReg(inf, addr)             __raw_readl(inf->preg->addr)
+#define LcdSetBit(inf, addr, msk)       __raw_writel((inf->regbak.addr |= (msk)), inf->preg->addr)
+#define LcdClrBit(inf, addr, msk)       __raw_writel((inf->regbak.addr &= ~(msk)), inf->preg->addr)
+#define LcdMskReg(inf, addr, msk, val)  (inf->regbak.addr)&=~(msk);   __raw_writel((inf->regbak.addr|=(val)), inf->preg->addr)
+*/
+#define LcdReadBit(inf, addr, msk)      ((inf->regbak.addr=inf->preg->addr)&(msk))
+#define LcdWrReg(inf, addr, val)        inf->preg->addr=inf->regbak.addr=(val)
+#define LcdRdReg(inf, addr)             (inf->preg->addr)
+#define LcdSetBit(inf, addr, msk)       inf->preg->addr=((inf->regbak.addr) |= (msk))
+#define LcdClrBit(inf, addr, msk)       inf->preg->addr=((inf->regbak.addr) &= ~(msk))
+#define LcdMskReg(inf, addr, msk, val)  (inf->regbak.addr)&=~(msk);   inf->preg->addr=(inf->regbak.addr|=(val))
+
+
+#define IsMcuLandscape()                ((SCREEN_MCU==inf->cur_screen->type) && ((90==inf->mcu_scandir)||(270==inf->mcu_scandir)))
+#define IsMcuUseFmk()                   ( (2==inf->cur_screen->mcu_usefmk) || ((1==inf->cur_screen->mcu_usefmk)&&IsMcuLandscape()) )
+
+#define CalScaleW1(x, y)                   (u32)( ((u32)x*0x1000)/y)
+#define CalScaleDownW0(x, y)               (u32)( (x>=y) ? ( ((u32)x*0x1000)/y) : (0x1000) )
+#define CalScaleUpW0(x, y)                 (u32)( (x<=y) ? ( ((u32)x*0x1000)/y) : (0x1000) )
+
+struct rk28fb_rgb {
+       struct fb_bitfield      red;
+       struct fb_bitfield      green;
+       struct fb_bitfield      blue;
+       struct fb_bitfield      transp;
+};
+
+static struct rk28fb_rgb def_rgb_16 = {
+     red:    { offset: 11, length: 5, },
+     green:  { offset: 5,  length: 6, },
+     blue:   { offset: 0,  length: 5, },
+     transp: { offset: 0,  length: 0, },
+};
+
+struct win0_fmk {
+    u8 completed;
+    u8 enable;
+       u8 format;
+       u32 addr_y[2];
+       u32 addr_uv[2];
+       u16 act_w[2];
+       u16 win_w[2];
+       u16 win_stx[2];
+       u32 addr_y2offset;
+       u32 addr_uv2offset;
+};
+
+struct win0_par {
+       u32 refcount;
+       u32     pseudo_pal[16];
+       u32 y_offset;
+       u32 uv_offset;
+
+       struct win0_fmk fmktmp;
+       struct win0_fmk fmk;
+    
+    u8 par_seted;
+    u8 addr_seted;
+};
+
+
+struct win1_fmk {
+    u8 completed;
+    u8 enable;
+       u32 addr[2];
+       u16 win_stx[2];
+       u16 act_w[2];
+       u32 addr2_offset;
+};
+
+struct win1_par {
+       u32 refcount;
+       u32     pseudo_pal[16];
+       int lstblank;
+       struct win1_fmk fmktmp;
+       struct win1_fmk fmk;
+};
+
+struct rk2818fb_inf {
+    struct fb_info *win0fb;
+    struct fb_info *win1fb;
+
+    void __iomem *reg_vir_base;  // virtual basic address of lcdc register
+       u32 reg_phy_base;       // physical basic address of lcdc register
+       u32 len;               // physical map length of lcdc register
+
+    struct clk      *clk;
+    struct clk      *dclk;            //lcdc dclk
+    struct clk      *dclk_parent;     //lcdc dclk divider frequency source
+    struct clk      *dclk_divider;    //lcdc demodulator divider frequency
+    unsigned long      dclk_rate;
+
+    /* lcdc reg base address and backup reg */
+    LCDC_REG *preg;
+    LCDC_REG regbak;
+
+       int in_suspend;
+
+    /* variable used in mcu panel */
+       int mcu_needflush;
+       int mcu_isrcnt;
+       u16 mcu_scandir;
+       struct timer_list mcutimer;
+       int mcu_status;
+       int mcu_ebooknew;
+       int mcu_usetimer;
+       int mcu_stopflush;
+       struct hrtimer htimer;
+       int mcu_fmkstate;
+
+    /* external memery */
+       char __iomem *screen_base2;
+    __u32 smem_len2;
+    unsigned long  smem_start2;
+
+    struct rk28fb_screen lcd_info;
+    struct rk28fb_screen tv_info[5];
+    struct rk28fb_screen hdmi_info[2];
+    struct rk28fb_screen *cur_screen;
+
+#ifdef CONFIG_ANDROID_POWER
+    android_early_suspend_t early_suspend;
+#endif
+};
+
+typedef enum _TRSP_MODE
+{
+    TRSP_CLOSE = 0,
+    TRSP_FMREG,
+    TRSP_FMREGEX,
+    TRSP_FMRAM,
+    TRSP_FMRAMEX,
+    TRSP_MASK,
+    TRSP_INVAL
+} TRSP_MODE;
+
+typedef enum _FMK_STATE
+{
+    FMK_IDLE = 0,
+    FMK_INT,
+    FMK_PRELEFT,
+    FMK_PREUP,
+    FMK_LEFT,
+    FMK_UP,
+    FMK_ENDING
+
+} FMK_STATE;
+
+
+struct platform_device *g_pdev = NULL;
+static int rk2818fb_suspend(struct platform_device *pdev, pm_message_t msg);
+static int win1fb_set_par(struct fb_info *info);
+
+#if FMK_USE_HARDTIMER
+int rk2818fb_dohardtimer(void);
+#endif
+
+#ifdef CONFIG_ANDROID_POWER
+static void rk2818fb_early_suspend(android_early_suspend_t *h);
+static void rk2818fb_early_resume(android_early_suspend_t *h);
+#endif
+
+
+#if 0
+#define CHK_SUSPEND(inf)       \
+       if(inf->in_suspend)     {       \
+               fbprintk(">>>>>> fb is in suspend! return! \n");        \
+               return -EPERM;  \
+       }
+#else
+#define CHK_SUSPEND(inf)
+#endif
+
+static DECLARE_WAIT_QUEUE_HEAD(wq);
+static int wq_condition = 0;
+
+void set_lcd_pin(struct platform_device *pdev, int enable)
+{
+    int ret =0;
+       struct rk2818_fb_mach_info *mach_info = pdev->dev.platform_data;
+
+       unsigned lcd_cs = mach_info->gpio->lcd_cs&0xffff;
+       unsigned display_on = mach_info->gpio->display_on&0xffff;
+       unsigned lcd_standby = mach_info->gpio->lcd_standby&0xffff;
+
+       int lcd_cs_pol = (mach_info->gpio->lcd_cs>>16)&0xffff;
+       int display_on_pol = (mach_info->gpio->display_on>>16)&0xffff;
+       int lcd_standby_pol = (mach_info->gpio->lcd_standby>>16)&0xffff;
+
+       fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__);
+       fbprintk(">>>>>> lcd_cs(%d) = %d \n", lcd_cs, enable ? lcd_cs_pol : !lcd_cs_pol);
+       fbprintk(">>>>>> display_on(%d) = %d \n", display_on, enable ? display_on_pol : !display_on_pol);
+       fbprintk(">>>>>> lcd_standby(%d) = %d \n", lcd_standby, enable ? lcd_standby_pol : !lcd_standby_pol);
+
+    // set cs and display_on
+    if(mach_info->gpio->lcd_cs)
+    {
+        ret = gpio_request(lcd_cs, NULL); 
+        if(ret != 0)
+        {
+            gpio_free(lcd_cs);
+            printk(KERN_ERR ">>>>>> lcd_cs gpio_request err \n ");
+            goto pin_err;
+        }
+        gpio_direction_output(lcd_cs, 0);
+               gpio_set_value(lcd_cs, enable ? lcd_cs_pol : !lcd_cs_pol);
+       }
+    if(mach_info->gpio->display_on) 
+    {
+        ret = gpio_request(display_on, NULL); 
+        if(ret != 0)
+        {
+            gpio_free(display_on);
+            printk(KERN_ERR ">>>>>> display_on gpio_request err \n ");
+            goto pin_err;
+        }
+        gpio_direction_output(display_on, 0);
+               gpio_set_value(display_on, enable ? display_on_pol : !display_on_pol);
+    }
+    if(mach_info->gpio->lcd_standby) 
+    {
+        ret = gpio_request(lcd_standby, NULL); 
+        if(ret != 0)
+        {
+            gpio_free(lcd_standby);
+            printk(KERN_ERR ">>>>>> lcd_standby gpio_request err \n ");
+            goto pin_err;
+        }
+        gpio_direction_output(lcd_standby, 0);
+               gpio_set_value(lcd_standby, enable ? lcd_standby_pol : !lcd_standby_pol);
+    }  
+    
+    return;
+pin_err:    
+    return;
+}
+
+int mcu_do_refresh(struct rk2818fb_inf *inf)
+{
+    if(inf->mcu_stopflush)  return 0;
+
+    if(SCREEN_MCU!=inf->cur_screen->type)   return 0;
+
+    // use frame mark
+    if(IsMcuUseFmk()) {
+        if(FMK_IDLE==inf->mcu_fmkstate) {
+            inf->mcu_fmkstate = FMK_INT;
+        } else {
+            inf->mcu_needflush = 1;
+            return (1);
+        }
+        return 0;
+    }
+
+    // not use frame mark
+    if(LcdReadBit(inf, MCU_TIMING_CTRL, m_MCU_HOLD_STATUS)) {
+        if(!LcdReadBit(inf, MCU_TIMING_CTRL, m_MCU_HOLD_STATUS)) {
+            inf->mcu_needflush = 1;
+        } else {
+            if(inf->cur_screen->refresh)    inf->cur_screen->refresh(REFRESH_PRE);
+            inf->mcu_needflush = 0;
+            inf->mcu_isrcnt = 0;
+            LcdSetBit(inf, MCU_TIMING_CTRL, m_MCU_HOLDMODE_FRAME_ST);
+        }
+    }
+    return 0;
+}
+
+
+void mcutimer_callback(unsigned long arg)
+{
+    struct rk2818fb_inf *inf = platform_get_drvdata(g_pdev);
+    static int waitcnt = 0;
+    static int newcnt = 0;
+
+    mod_timer(&inf->mcutimer, jiffies + HZ/10);
+
+    switch(inf->mcu_status)
+    {
+    case MS_IDLE:
+        if(OUT_P16BPP4==inf->cur_screen->face) {
+            inf->mcu_status = MS_EBOOK;
+        } else {
+            inf->mcu_status = MS_MCU;
+        }
+        break;
+    case MS_MCU:
+        if(inf->mcu_usetimer)   mcu_do_refresh(inf);
+        break;
+    case MS_EBOOK:
+        if(inf->mcu_ebooknew) {
+            inf->mcu_ebooknew = 0;
+            inf->mcu_status = MS_EWAITSTART;
+            newcnt = 0;
+        }
+        break;
+    case MS_EWAITSTART:
+        if(inf->mcu_ebooknew) {
+            inf->mcu_ebooknew = 0;
+            if(newcnt++>10) {
+                inf->mcu_status = MS_EWAITEND;
+                waitcnt = 0;
+            }
+        } else {
+            inf->mcu_status = MS_EWAITEND;
+            waitcnt = 0;
+        }
+        break;
+    case MS_EWAITEND:
+        if(0==waitcnt) {
+            mcu_do_refresh(inf);
+        }
+        if(waitcnt++>14) {
+            inf->mcu_status = MS_EEND;
+        }
+        break;
+    case MS_EEND:
+        inf->mcu_status = MS_MCU;
+        break;
+    default:
+        inf->mcu_status = MS_MCU;
+        break;
+    }
+}
+
+int mcu_refresh(struct rk2818fb_inf *inf)
+{
+    static int mcutimer_inited = 0;
+
+    if(SCREEN_MCU!=inf->cur_screen->type)   return 0;
+
+    if(!mcutimer_inited) {
+        mcutimer_inited = 1;
+        init_timer(&inf->mcutimer);
+        inf->mcutimer.function = mcutimer_callback;
+        inf->mcutimer.expires = jiffies + HZ/5;
+        inf->mcu_status = 0;
+        add_timer(&inf->mcutimer);
+    }
+
+    inf->mcu_ebooknew = 1;
+    if(MS_MCU==inf->mcu_status)     mcu_do_refresh(inf);
+
+    return 0;
+}
+
+int init_lcdc(struct fb_info *info)
+{
+    struct rk2818fb_inf *inf = dev_get_drvdata(info->device);
+    u32 reg1=0, reg2=0, msk=0, clr=0;
+
+       fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__);
+    fbprintk(">>>>>> inf %x ; inf->regbak%x ; inf->preg %x \n", inf, &inf->regbak, inf->preg);
+    fbprintk(">>>>>> %x ; %x \n", &(inf->regbak.SYS_CONFIG), &(inf->preg->SYS_CONFIG));
+       // set AHB access rule and disable all windows
+    LcdMskReg(inf, SYS_CONFIG,
+        m_W1_ROLLER | m_W0_ROLLER | m_INTERIACE_EN | m_MPEG2_I2P_EN | m_W0_ROTATE |
+        m_W1_ENABLE |m_W0_ENABLE | m_HWC_ENABLE | m_HWC_RELOAD_EN |m_W1_INTERLACE_READ |
+        m_W0_INTERLACE_READ | m_STANDBY | m_W1_HWC_INCR|
+        m_W1_HWC_BURST | m_W0_INCR | m_W0_BURST ,
+        v_W1_ROLLER(0) | v_W0_ROLLER(0) | v_INTERIACE_EN(0) |
+        v_MPEG2_I2P_EN(0) | v_W0_ROTATE(0) |v_W1_ENABLE(0) |
+        v_W0_ENABLE(0) | v_HWC_ENABLE(0) | v_HWC_RELOAD_EN(0) | v_W1_INTERLACE_READ(0) | 
+        v_W0_INTERLACE_READ(0) | v_STANDBY(0) | v_W1_HWC_INCR(31) | v_W1_HWC_BURST(1) |
+        v_W0_INCR(31) | v_W0_BURST(1)
+        ); // use ahb burst32
+
+       // set all swap rule for every window and set water mark
+    reg1 = v_W0_565_RB_SWAP(0) | v_W0_YRGB_M8_SWAP(0) |
+           v_W0_YRGB_R_SHIFT_SWAP(0) | v_W0_CBR_R_SHIFT_SWAP(0) | v_W0_YRGB_16_SWAP(0) |
+           v_W0_YRGB_8_SWAP(0) | v_W0_CBR_16_SWAP(0) | v_W0_CBR_8_SWAP(0) | v_W0_YRGB_HL8_SWAP(0);
+           
+    reg2 = v_W1_565_RB_SWAP(0) |  v_W1_16_SWAP(0) | v_W1_8_SWAP(0) |
+           v_W1_R_SHIFT_SWAP(0) | v_OUTPUT_BG_SWAP(0) | v_OUTPUT_RB_SWAP(0) | v_OUTPUT_RG_SWAP(0) |
+           v_DELTA_SWAP(0) | v_DUMMY_SWAP(0);
+              
+    LcdWrReg(inf, SWAP_CTRL, reg1 | reg2);
+       
+       // and mcu holdmode; and set win1 top.
+    LcdMskReg(inf, MCU_TIMING_CTRL, m_MCU_HOLDMODE_SELECT | m_MCU_HOLDMODE_FRAME_ST | m_MCU_BYPASSMODE_SELECT ,
+            v_MCU_HOLDMODE_SELECT(0)| v_MCU_HOLDMODE_FRAME_ST(0) |v_MCU_BYPASSMODE_SELECT(0));
+
+    // disable blank out, black out, tristate out, yuv2rgb bypass
+    LcdMskReg(inf, BLEND_CTRL, m_W1_BLEND_EN | m_W0_BLEND_EN | m_HWC_BLEND_EN | m_W1_BLEND_FACTOR_SELECT |
+             m_W0_BLEND_FACTOR_SELECT | m_W0W1_OVERLAY | m_HWC_BLEND_FACTOR | m_W1_BLEND_FACTOR | m_W0_BLEND_FACTOR, 
+             v_W1_BLEND_EN(0) | v_W0_BLEND_EN(0) | v_HWC_BLEND_EN(0) | v_W1_BLEND_FACTOR_SELECT(0) |
+             v_W0_BLEND_FACTOR_SELECT(0) | v_W0W1_OVERLAY(0) | v_HWC_BLEND_FACTOR(0) | v_W1_BLEND_FACTOR(0) | v_W0_BLEND_FACTOR(0) 
+             );
+    
+    LcdMskReg(inf, WIN0_COLOR_KEY_CTRL, m_COLORKEY_EN, v_COLORKEY_EN(0));
+    LcdMskReg(inf, WIN1_COLOR_KEY_CTRL, m_COLORKEY_EN, v_COLORKEY_EN(0));
+    
+    LcdMskReg(inf, DSP_CTRL0, m_HSYNC_POLARITY | m_VSYNC_POLARITY | m_DEN_POLARITY | m_DCLK_POLARITY | 
+        m_COLOR_SPACE_CONVERSION | m_DITHERING_EN | m_INTERLACE_FIELD_POLARITY | 
+        m_YUV_CLIP_MODE | m_I2P_FILTER_EN , 
+        v_HSYNC_POLARITY(0) | v_VSYNC_POLARITY(0) | v_DEN_POLARITY(0) | v_DCLK_POLARITY(0) | v_COLOR_SPACE_CONVERSION(0) | 
+        v_DITHERING_EN(0) | v_INTERLACE_FIELD_POLARITY(0) | v_YUV_CLIP_MODE(0) | v_I2P_FILTER_EN(0));
+    
+    LcdMskReg(inf, DSP_CTRL1, m_BG_COLOR | m_BLANK_MODE | m_BLACK_MODE | m_W1_SD_DEFLICKER_EN | m_W1_SP_DEFLICKER_EN | 
+            m_W0CR_SD_DEFLICKER_EN | m_W0CR_SP_DEFLICKER_EN | m_W0YRGB_SD_DEFLICKER_EN | m_W0YRGB_SP_DEFLICKER_EN, 
+            v_BG_COLOR(0) | v_BLANK_MODE(0) | v_BLACK_MODE(0) | v_W1_SD_DEFLICKER_EN(0) | v_W1_SP_DEFLICKER_EN(0) | 
+            v_W0CR_SD_DEFLICKER_EN(0) | v_W0CR_SP_DEFLICKER_EN(0) | v_W0YRGB_SD_DEFLICKER_EN(0) | v_W0YRGB_SP_DEFLICKER_EN(0));
+
+    // initialize all interrupt
+    clr = v_HOR_STARTCLEAR(1) | v_FRM_STARTCLEAR(1) | v_SCANNING_CLEAR(1);
+        
+    msk = v_HOR_STARTMASK(1) | v_FRM_STARTMASK(0) | v_SCANNING_MASK(1);
+
+    LcdWrReg(inf, INT_STATUS, clr | msk);
+
+       // let above to take effect
+    LcdWrReg(inf, REG_CFG_DONE, 0x01);
+
+    return 0;
+}
+
+void load_screen(struct fb_info *info, bool initscreen)
+{
+    int ret = -EINVAL;
+    struct rk2818fb_inf *inf = dev_get_drvdata(info->device);
+    struct rk28fb_screen *screen = inf->cur_screen;
+    u16 face = screen->face;
+    u16 mcu_total, mcu_rwstart, mcu_csstart, mcu_rwend, mcu_csend;
+    u16 right_margin = screen->right_margin, lower_margin = screen->lower_margin;
+    u16 x_res = screen->x_res, y_res = screen->y_res;
+    u32 clk_rate = 0;
+    u32 dclk_rate = 0;
+        
+       fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__);
+
+//     if(OUT_P16BPP4==face)   face = OUT_P565;
+
+    // set the rgb or mcu
+    LcdMskReg(inf, MCU_TIMING_CTRL, m_MCU_OUTPUT_SELECT, v_MCU_OUTPUT_SELECT((SCREEN_MCU==screen->type)?(1):(0)));
+    /*
+
+       // set out format and mcu timing
+    mcu_total  = (screen->mcu_wrperiod*150*1000)/1000000;
+    if(mcu_total>31)    mcu_total = 31;
+    if(mcu_total<3)     mcu_total = 3;
+    mcu_rwstart = (mcu_total+1)/4 - 1;
+    mcu_rwend = ((mcu_total+1)*3)/4 - 1;
+    mcu_csstart = (mcu_rwstart>2) ? (mcu_rwstart-3) : (0);
+    mcu_csend = (mcu_rwend>15) ? (mcu_rwend-1) : (mcu_rwend);
+
+    fbprintk(">> mcu_total=%d, mcu_rwstart=%d, mcu_csstart=%d, mcu_rwend=%d, mcu_csend=%d \n",
+        mcu_total, mcu_rwstart, mcu_csstart, mcu_rwend, mcu_csend);
+
+    LcdMskReg(inf, MCU_TIMING_CTRL,
+             m_MCU_CS_ST | m_MCU_CS_END| m_MCU_RW_ST | m_MCU_RW_END |
+             m_MCU_WRITE_PERIOD | m_MCU_HOLDMODE_SELECT | m_MCU_HOLDMODE_FRAME_ST,
+            v_MCU_CS_ST(mcu_csstart) | v_MCU_CS_END(mcu_csend) | v_MCU_RW_ST(mcu_rwstart) |
+            v_MCU_RW_END(mcu_rwend) |  v_MCU_WRITE_PERIOD(mcu_total) |
+            v_MCU_HOLDMODE_SELECT((SCREEN_MCU==screen->type)?(1):(0)) | v_MCU_HOLDMODE_FRAME_ST(0)
+           );
+*/
+       // set synchronous pin polarity and data pin swap rule
+     LcdMskReg(inf, DSP_CTRL0,
+        m_DISPLAY_FORMAT | m_HSYNC_POLARITY | m_VSYNC_POLARITY | m_DEN_POLARITY |
+        m_DCLK_POLARITY | m_COLOR_SPACE_CONVERSION,
+        v_DISPLAY_FORMAT(face) | v_HSYNC_POLARITY(screen->pin_hsync) | v_VSYNC_POLARITY(screen->pin_vsync) |
+        v_DEN_POLARITY(screen->pin_den) | v_DCLK_POLARITY(screen->pin_dclk) | v_COLOR_SPACE_CONVERSION(0)        
+        );
+
+     LcdMskReg(inf, DSP_CTRL1, m_BG_COLOR,  v_BG_COLOR(0xff0000) );
+
+     LcdMskReg(inf, SWAP_CTRL, m_OUTPUT_RB_SWAP | m_OUTPUT_RG_SWAP | m_DELTA_SWAP | m_DUMMY_SWAP,
+            v_OUTPUT_RB_SWAP(screen->swap_rb) | v_OUTPUT_RG_SWAP(screen->swap_rg) | v_DELTA_SWAP(screen->swap_delta) | v_DUMMY_SWAP(screen->swap_dumy));
+
+       // set horizontal & vertical out timing
+       if(IsMcuLandscape()) 
+    {
+        x_res = (screen->mcu_usefmk) ? (screen->y_res/2) : (screen->y_res);
+        y_res = screen->x_res;
+       }
+       if(SCREEN_MCU==inf->cur_screen->type) 
+    {
+           right_margin = x_res/6;
+       }
+
+    LcdMskReg(inf, DSP_HTOTAL_HS_END, m_BIT11LO | m_BIT11HI, v_BIT11LO(screen->hsync_len) | 
+             v_BIT11HI(screen->hsync_len + screen->left_margin + x_res + right_margin));
+    LcdMskReg(inf, DSP_HACT_ST_END, m_BIT11LO | m_BIT11HI, v_BIT11LO(screen->hsync_len + screen->left_margin + x_res) | 
+             v_BIT11HI(screen->hsync_len + screen->left_margin));        
+
+         
+    LcdMskReg(inf, DSP_VTOTAL_VS_END, m_BIT11LO | m_BIT11HI, v_BIT11LO(screen->vsync_len) | 
+              v_BIT11HI(screen->vsync_len + screen->upper_margin + y_res + lower_margin));
+    LcdMskReg(inf, DSP_VACT_ST_END, m_BIT11LO | m_BIT11HI,  v_BIT11LO(screen->vsync_len + screen->upper_margin+y_res)| 
+              v_BIT11HI(screen->vsync_len + screen->upper_margin));
+  
+    LcdMskReg(inf, DSP_VS_ST_END_F1, m_BIT11LO | m_BIT11HI, v_BIT11LO(0) | v_BIT11HI(0));  
+    LcdMskReg(inf, DSP_VACT_ST_END_F1, m_BIT11LO | m_BIT11HI, v_BIT11LO(0) | v_BIT11HI(0));
+  
+       // let above to take effect
+    LcdWrReg(inf, REG_CFG_DONE, 0x01);
+
+    // set lcdc clk
+    if(SCREEN_MCU==screen->type)    screen->pixclock = 150; //mcu fix to 150 MHz
+
+    clk_set_parent(inf->dclk_divider, inf->dclk_parent);
+    clk_set_parent(inf->dclk, inf->dclk_divider);
+
+    //clk_set_parent(inf->dclk, inf->dclk_parent);
+
+    clk_rate = clk_get_rate(inf->dclk_parent);
+
+    dclk_rate = screen->pixclock * 1000000;
+    
+    printk(">>>>>> set lcdc dclk need %d HZ, clk_parent = %d hz \n ", screen->pixclock, clk_rate);
+
+    if(clk_rate < dclk_rate)
+    {
+         clk_rate = dclk_rate;
+         ret = clk_set_rate(inf->dclk_parent, clk_rate);
+         if(ret)
+         {
+             printk(KERN_ERR ">>>>>> set lcdc dclk_parent faild  clk_rate = %d  \n ", clk_rate);
+         }        
+    }
+    else if((clk_rate > dclk_rate) && (clk_rate % dclk_rate))
+    {
+        clk_rate = clk_rate/dclk_rate * dclk_rate;
+        ret = clk_set_rate(inf->dclk_parent, clk_rate);
+        if(ret)
+        {
+            printk(KERN_ERR ">>>>>> set lcdc dclk_parent faild clk_rate = %d \n ", clk_rate);
+        }        
+    }
+
+    ret = clk_set_rate(inf->dclk_divider, dclk_rate);
+    
+    if(ret)
+    {
+        printk(KERN_ERR ">>>>>> set lcdc dclk_divider faild \n ");
+    }    
+  
+    clk_enable(inf->dclk);
+  //  clk_enable(inf->clk);
+
+    // init screen panel
+    if(screen->init && initscreen)
+       screen->init();
+}
+
+static inline unsigned int chan_to_field(unsigned int chan,
+                                        struct fb_bitfield *bf)
+{
+       chan &= 0xffff;
+       chan >>= 16 - bf->length;
+       return chan << bf->offset;
+}
+
+static int fb_setcolreg(unsigned regno,
+                              unsigned red, unsigned green, unsigned blue,
+                              unsigned transp, struct fb_info *info)
+{
+       unsigned int val;
+//     fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__);
+
+       switch (info->fix.visual) {
+       case FB_VISUAL_TRUECOLOR:
+               /* true-colour, use pseudo-palette */
+               if (regno < 16) {
+                       u32 *pal = info->pseudo_palette;
+                       val  = chan_to_field(red,   &info->var.red);
+                       val |= chan_to_field(green, &info->var.green);
+                       val |= chan_to_field(blue,  &info->var.blue);
+                       pal[regno] = val;
+               }
+               break;
+       default:
+               return -1;      /* unknown type */
+       }
+
+       return 0;
+}
+
+static int win0fb_blank(int blank_mode, struct fb_info *info)
+{
+    struct rk2818fb_inf *inf = dev_get_drvdata(info->device);
+    struct win0_par *par = info->par;
+
+    fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__);
+
+       CHK_SUSPEND(inf);
+
+    switch(blank_mode)
+    {
+    case FB_BLANK_UNBLANK:
+        LcdMskReg(inf, SYS_CONFIG, m_W0_ENABLE, v_W0_ENABLE(1));
+        par->fmktmp.enable = 1;
+        par->fmktmp.completed = 1;
+        break;
+    default:
+        LcdMskReg(inf, SYS_CONFIG, m_W0_ENABLE, v_W0_ENABLE(0));
+        par->fmktmp.enable = 0;
+        par->fmktmp.completed = 1;
+        break;
+    }
+    LcdWrReg(inf, REG_CFG_DONE, 0x01);
+
+       mcu_refresh(inf);
+    return 0;
+}
+
+static int win0fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+    struct rk2818fb_inf *inf = dev_get_drvdata(info->device);
+    struct rk28fb_screen *screen = inf->cur_screen;
+
+    u32 ScaleYUpY=0x1000, ScaleYDnY=0x1000;   
+    u16 xpos = (var->nonstd>>8) & 0xfff;   //offset in panel
+    u16 ypos = (var->nonstd>>20) & 0xfff;
+    u16 xsize = (var->grayscale>>8) & 0xfff;   //visiable size in panel
+    u16 ysize = (var->grayscale>>20) & 0xfff;
+    u16 xlcd = screen->x_res;        //size of panel
+    u16 ylcd = screen->y_res;
+
+    if(IsMcuLandscape()) 
+    {
+        xlcd = screen->y_res;
+        ylcd = screen->x_res;
+    }
+
+    fbprintk(">>>>>> %s : %s\n", __FILE__, __FUNCTION__);
+
+       CHK_SUSPEND(inf);
+
+    if( 0==var->xres_virtual || 0==var->yres_virtual ||
+        0==var->xres || 0==var->yres || var->xres<16 ||
+        0==xsize || 0==ysize || xsize<16 ||
+        ((16!=var->bits_per_pixel)&&(32!=var->bits_per_pixel)) )
+    {
+        printk(">>>>>> win0fb_check_var fail 1!!! \n");
+               printk("0==%d || 0==%d || 0==%d || 0==%d || %d<16 \n ||0==%d || 0==%d || %d<16 ||((16!=%d)&&(32!=%d)) \n", 
+                               var->xres_virtual, var->yres_virtual, var->xres, var->yres, var->xres, xsize, ysize, xsize,
+                       var->bits_per_pixel, var->bits_per_pixel);
+        return -EINVAL;
+    }
+
+    if( (var->xoffset+var->xres)>var->xres_virtual ||
+        (var->yoffset+var->yres)>var->yres_virtual ||
+        (xpos+xsize)>xlcd || (ypos+ysize)>ylcd )
+    {
+        printk(">>>>>> win0fb_check_var fail 2!!! \n");
+               printk("(%d+%d)>%d || (%d+%d)>%d || (%d+%d)>%d || (%d+%d)>%d \n ",
+                               var->xoffset, var->xres, var->xres_virtual, var->yoffset, var->yres, 
+                               var->yres_virtual, xpos, xsize, xlcd, ypos, ysize, ylcd);
+        return -EINVAL;
+    }   
+
+    switch(var->nonstd&0xff)
+    {
+    case 0: // rgb
+        switch(var->bits_per_pixel)
+        {
+        case 16:    // rgb565
+            var->xres_virtual = (var->xres_virtual + 0x1) & (~0x1);
+            var->xres = (var->xres + 0x1) & (~0x1);
+            var->xoffset = (var->xoffset) & (~0x1);
+            break;
+        default:    // rgb888
+            var->bits_per_pixel = 32;
+            break;
+        }
+        break;
+    case 1: // yuv422
+        var->xres_virtual = (var->xres_virtual + 0x3) & (~0x3);
+        var->xres = (var->xres + 0x3) & (~0x3);
+        var->xoffset = (var->xoffset) & (~0x3);
+        break;
+    case 2: // yuv4200
+        var->xres_virtual = (var->xres_virtual + 0x3) & (~0x3);
+        var->yres_virtual = (var->yres_virtual + 0x1) & (~0x1);
+        var->xres = (var->xres + 0x3) & (~0x3);
+        var->yres = (var->yres + 0x1) & (~0x1);
+        var->xoffset = (var->xoffset) & (~0x3);
+        var->yoffset = (var->yoffset) & (~0x1);
+        break;
+    case 3: // yuv4201
+        var->xres_virtual = (var->xres_virtual + 0x3) & (~0x3);
+        var->yres_virtual = (var->yres_virtual + 0x1) & (~0x1);
+        var->xres = (var->xres + 0x3) & (~0x3);
+        var->yres = (var->yres + 0x1) & (~0x1);
+        var->xoffset = (var->xoffset) & (~0x3);
+        var->yoffset = (var->yoffset) & (~0x1);
+        break;
+    case 4: // yuv420m
+        var->xres_virtual = (var->xres_virtual + 0x7) & (~0x7);
+        var->yres_virtual = (var->yres_virtual + 0x1) & (~0x1);
+        var->xres = (var->xres + 0x7) & (~0x7);
+        var->yres = (var->yres + 0x1) & (~0x1);
+        var->xoffset = (var->xoffset) & (~0x7);
+        var->yoffset = (var->yoffset) & (~0x1);
+        break;
+    case 5: // yuv444
+        var->xres_virtual = (var->xres_virtual + 0x3) & (~0x3);
+        var->xres = (var->xres + 0x3) & (~0x3);
+        var->xoffset = (var->xoffset) & (~0x3);
+        break;
+    default:
+        printk(">>>>>> win0fb var->nonstd=%d is invalid! \n", var->nonstd);
+        return -EINVAL;
+    }
+
+    ScaleYDnY = CalScaleDownW0(var->yres, ysize);
+    ScaleYUpY = CalScaleUpW0(var->yres, ysize);
+
+    if((ScaleYDnY>0x8000) || (ScaleYUpY<=0x200))
+    {
+        return -EINVAL;        // multiple of scale down or scale up can't exceed 8
+    }    
+    
+    return 0;
+}
+
+static int win0fb_set_par(struct fb_info *info)
+{
+    struct rk2818fb_inf *inf = dev_get_drvdata(info->device);
+    struct rk28fb_screen *screen = inf->cur_screen;
+    struct fb_var_screeninfo *var = &info->var;
+    struct fb_fix_screeninfo *fix = &info->fix;
+    struct win0_par *par = info->par;
+
+    u8 format = 0;
+    dma_addr_t map_dma;
+    u32 y_offset=0, uv_offset=0, cblen=0, crlen=0, map_size=0, smem_len=0;
+    u16 xres=var->xres;
+    u16 xpos = (var->nonstd>>8) & 0xfff;
+    u16 ypos = (var->nonstd>>20) & 0xfff;
+    u16 xsize = (var->grayscale>>8) & 0xfff;
+    u16 ysize = (var->grayscale>>20) & 0xfff;
+    u32 win0_en = var->reserved[2];
+    u32 y_addr = var->reserved[3];
+    u32 uv_addr = var->reserved[4];
+
+    u32 ScaleYUpX=0x1000, ScaleYDnX=0x1000, ScaleYUpY=0x1000, ScaleYDnY=0x1000;
+    u32 ScaleCbrUpX=0x1000, ScaleCbrDnX=0x1000, ScaleCbrUpY=0x1000, ScaleCbrDnY=0x1000;
+
+    fbprintk(">>>>>> %s : %s\n", __FILE__, __FUNCTION__);
+
+       CHK_SUSPEND(inf);
+
+       /* calculate y_offset,uv_offset,line_length,cblen and crlen  */
+    switch(var->nonstd&0xff)
+    {
+    case 0: // rgb
+        switch(var->bits_per_pixel)
+        {
+        case 16:    // rgb565
+            format = 1;
+            fix->line_length = 2 * var->xres_virtual;
+            y_offset = (var->yoffset*var->xres_virtual + var->xoffset)*2;
+            break;
+        case 32:    // rgb888
+            format = 0;
+            fix->line_length = 4 * var->xres_virtual;
+            y_offset = (var->yoffset*var->xres_virtual + var->xoffset)*4;
+            break;
+        default:
+            return -EINVAL;
+        }
+        break;
+    case 1: // yuv422
+        format = 2;
+        fix->line_length = var->xres_virtual;
+        y_offset = var->yoffset*var->xres_virtual + var->xoffset;
+        uv_offset = var->yoffset*var->xres_virtual + var->xoffset;
+        cblen = crlen = (var->xres_virtual*var->yres_virtual)/2;
+        break;
+    case 2: // yuv4200
+        format = 3;
+        fix->line_length = var->xres_virtual;
+        y_offset = var->yoffset*var->xres_virtual + var->xoffset;
+        uv_offset = (var->yoffset/2)*var->xres_virtual + var->xoffset;
+        cblen = crlen = (var->xres_virtual*var->yres_virtual)/4;
+        break;
+    case 3: // yuv4201
+        format = 4;
+        fix->line_length = var->xres_virtual;
+        y_offset = (var->yoffset/2)*2*var->xres_virtual + (var->xoffset)*2;
+        uv_offset = (var->yoffset/2)*var->xres_virtual + var->xoffset;
+        cblen = crlen = (var->xres_virtual*var->yres_virtual)/4;
+        break;
+    case 4: // yuv420m
+        format = 5;
+        fix->line_length = var->xres_virtual;
+        y_offset = (var->yoffset/2)*3*var->xres_virtual + (var->xoffset)*3;
+        cblen = crlen = (var->xres_virtual*var->yres_virtual)/4;
+        break;
+    case 5: // yuv444
+        format = 6;
+        fix->line_length = var->xres_virtual;
+        y_offset = var->yoffset*var->xres_virtual + var->xoffset;
+        uv_offset = var->yoffset*2*var->xres_virtual + var->xoffset*2;
+        cblen = crlen = (var->xres_virtual*var->yres_virtual);
+        break;
+    default:
+        return -EINVAL;
+    }
+
+    smem_len = fix->line_length * var->yres_virtual + cblen + crlen;
+    map_size = PAGE_ALIGN(smem_len);
+
+    if(y_addr && uv_addr)  // buffer alloced by user
+    {
+        if (info->screen_base) {
+            printk(">>>>>> win0fb unmap memory(%d)! \n", info->fix.smem_len);
+            dma_free_writecombine(NULL, PAGE_ALIGN(info->fix.smem_len),info->screen_base, info->fix.smem_start);
+               info->screen_base = 0;
+        }
+        fix->smem_start = y_addr;
+        fix->smem_len = smem_len;
+        fix->mmio_start = uv_addr;
+
+        par->addr_seted = ((-1==(int)y_addr)&&(-1==(int)uv_addr)) ? 0 : 1;
+    }
+    else    // driver alloce buffer
+    {
+        if ( (smem_len != fix->smem_len) || !info->screen_base )     // buffer need realloc
+        {
+            fbprintk(">>>>>> win0 buffer size is change! remap memory!\n");
+            fbprintk(">>>>>> smem_len %d = %d * %d + %d + %d\n", smem_len, fix->line_length, var->yres_virtual, cblen, crlen);
+            fbprintk(">>>>>> map_size = %d\n", map_size);
+            LcdMskReg(inf, SYS_CONFIG, m_W0_ENABLE, v_W0_ENABLE(0));
+            LcdWrReg(inf, REG_CFG_DONE, 0x01);
+            msleep(50);
+            if (info->screen_base) {
+                   fbprintk(">>>>>> win0fb unmap memory(%d)! \n", info->fix.smem_len);
+                   dma_free_writecombine(NULL, PAGE_ALIGN(info->fix.smem_len),info->screen_base, info->fix.smem_start);
+                   info->screen_base = 0;
+                   fix->smem_start = 0;
+                   fix->smem_len = 0;
+           }
+
+           info->screen_base = dma_alloc_writecombine(NULL, map_size, &map_dma, GFP_KERNEL);
+            if(!info->screen_base) {
+                printk(">>>>>> win0fb dma_alloc_writecombine fail!\n");
+                return -ENOMEM;
+            }
+            memset(info->screen_base, 0x00, map_size);
+            fix->smem_start = map_dma;
+            fix->smem_len = smem_len;
+            fix->mmio_start = fix->smem_start + fix->line_length * var->yres_virtual;
+            fbprintk(">>>>>> alloc succ, smem_start=%08x, smem_len=%d, mmio_start=%d!\n",
+                (u32)fix->smem_start, fix->smem_len, (u32)fix->mmio_start);
+        }
+    }
+
+    par->y_offset = y_offset;
+    par->uv_offset = uv_offset;
+
+       // calculate the display phy address
+    y_addr = fix->smem_start + y_offset;
+    uv_addr = fix->mmio_start + uv_offset;
+    fbprintk("y_addr 0x%08x = 0x%08x + %d\n", y_addr, (u32)fix->smem_start, y_offset);
+    fbprintk("uv_addr 0x%08x = 0x%08x + %d\n", uv_addr, (u32)fix->mmio_start , uv_offset);
+
+    if((var->xres>1280) && (xsize>1280))
+    {
+        ScaleYDnX = CalScaleDownW0(var->xres, 1280);
+        ScaleYUpX = CalScaleUpW0(1280, xsize);
+    }
+    else
+    {
+        ScaleYDnX = CalScaleDownW0(var->xres, xsize);
+        ScaleYUpX = CalScaleUpW0(var->xres, xsize);
+    }
+
+    ScaleYDnY = CalScaleDownW0(var->yres, ysize);
+    ScaleYUpY = CalScaleUpW0(var->yres, ysize);
+
+    switch(var->nonstd&0xff)
+    {
+       case 0: // rgb
+       case 1:// yuv422
+           if((var->xres>1280) && (xsize>1280))
+           {
+               ScaleCbrDnX= CalScaleDownW0((var->xres/2), 1280);   
+               ScaleCbrUpX = CalScaleUpW0((640), xsize); 
+           }
+           else             
+           {
+               if(var->rotate) 
+               {
+                   ScaleCbrDnX= CalScaleDownW0(var->xres, xsize);   
+                   ScaleCbrUpX = CalScaleUpW0(var->xres, xsize); 
+               }
+               else
+               {
+                   ScaleCbrDnX= CalScaleDownW0((var->xres/2), xsize);   
+                   ScaleCbrUpX = CalScaleUpW0((var->xres/2), xsize);   
+               }
+           }        
+           
+           ScaleCbrDnY =  CalScaleDownW0(var->yres, ysize);  
+           ScaleCbrUpY =  CalScaleUpW0(var->yres, ysize); 
+           break;
+       case 2: // yuv4200
+       case 3: // yuv4201
+       case 4: // yuv420m                   
+           if((var->xres>1280) && (xsize>1280))
+           {
+               ScaleCbrDnX= CalScaleDownW0(var->xres/2, 1280);   
+               ScaleCbrUpX = CalScaleUpW0(640, xsize); 
+           }
+           else
+           {
+               ScaleCbrDnX= CalScaleDownW0(var->xres/2, xsize);   
+               ScaleCbrUpX = CalScaleUpW0(var->xres/2, xsize); 
+           }
+           
+           ScaleCbrDnY =  CalScaleDownW0(var->yres/2, ysize);  
+           ScaleCbrUpY =  CalScaleUpW0(var->yres/2, ysize);  
+           break;
+       case 5:// yuv444
+           if((var->xres>1280) && (xsize>1280))
+           {
+               ScaleCbrDnX= CalScaleDownW0(var->xres, 1280);   
+               ScaleCbrUpX = CalScaleUpW0(1280, xsize);   
+           }
+           else
+           {
+               ScaleCbrDnX= CalScaleDownW0(var->xres, xsize);   
+               ScaleCbrUpX = CalScaleUpW0(var->xres, xsize); 
+           }
+           ScaleCbrDnY =  CalScaleDownW0(var->yres, ysize);  
+           ScaleCbrUpY =  CalScaleUpW0(var->yres, ysize);    
+           break;
+    }
+        
+    xpos += LcdReadBit(inf, DSP_HACT_ST_END, m_BIT11HI);
+    ypos += LcdReadBit(inf, DSP_VACT_ST_END, m_BIT11HI);
+
+    LcdWrReg(inf, WIN0_YRGB_MST, y_addr);
+    LcdWrReg(inf, WIN0_CBR_MST, uv_addr);
+
+    LcdMskReg(inf, SYS_CONFIG, m_W0_ENABLE | m_W0_FORMAT,
+        v_W0_ENABLE(win0_en) | v_W0_FORMAT(format));
+    
+    LcdMskReg(inf, WIN0_VIR, m_WORDLO | m_WORDHI, v_VIRWIDTH(var->xres_virtual) | v_VIRHEIGHT((var->yres_virtual)) );
+    LcdMskReg(inf, WIN0_ACT_INFO, m_WORDLO | m_WORDHI, v_WORDLO(xres) | v_WORDHI(var->yres));
+    LcdMskReg(inf, WIN0_DSP_ST, m_BIT11LO | m_BIT11HI, v_BIT11LO(xpos) | v_BIT11HI(ypos));
+    LcdMskReg(inf, WIN0_DSP_INFO, m_BIT11LO | m_BIT11HI,  v_BIT11LO(xsize) | v_BIT11HI(ysize));
+    LcdMskReg(inf, WIN0_SD_FACTOR_Y, m_WORDLO | m_WORDHI, v_WORDLO(ScaleYDnX) | v_WORDHI(ScaleYDnY));
+    LcdMskReg(inf, WIN0_SP_FACTOR_Y, m_WORDLO | m_WORDHI, v_WORDLO(ScaleYUpX) | v_WORDHI(ScaleYUpY)); 
+    LcdMskReg(inf, WIN0_SD_FACTOR_CBR, m_WORDLO | m_WORDHI, v_WORDLO(ScaleCbrDnX) | v_WORDHI(ScaleCbrDnY));
+    LcdMskReg(inf, WIN0_SP_FACTOR_CBR, m_WORDLO | m_WORDHI, v_WORDLO(ScaleCbrUpX) | v_WORDHI(ScaleCbrUpY));    
+    LcdMskReg(inf, DSP_CTRL0, m_I2P_THRESHOLD_Y | m_I2P_THRESHOLD_CBR | m_I2P_CUR_POLARITY | m_DROP_LINE_W0,
+                         v_I2P_THRESHOLD_Y(0) | v_I2P_THRESHOLD_CBR(0)| v_I2P_CUR_POLARITY(0) | v_DROP_LINE_W0(0));
+
+    switch(format)
+    {
+    case 0:
+         LcdMskReg(inf, SWAP_CTRL, m_W0_YRGB_8_SWAP | m_W0_YRGB_16_SWAP | m_W0_YRGB_R_SHIFT_SWAP | m_W0_565_RB_SWAP | m_W0_YRGB_M8_SWAP | m_W0_CBR_8_SWAP | m_W0_YRGB_HL8_SWAP,
+            v_W0_YRGB_8_SWAP(0) | v_W0_YRGB_16_SWAP(0) | v_W0_YRGB_R_SHIFT_SWAP(0) | v_W0_565_RB_SWAP(0)| v_W0_YRGB_M8_SWAP(0)| v_W0_CBR_8_SWAP(0) | v_W0_YRGB_HL8_SWAP(0) );
+        break;
+    case 1:
+        LcdMskReg(inf, SWAP_CTRL, m_W0_YRGB_8_SWAP | m_W0_YRGB_16_SWAP | m_W0_YRGB_R_SHIFT_SWAP | m_W0_565_RB_SWAP | m_W0_YRGB_M8_SWAP | m_W0_CBR_8_SWAP  | m_W0_YRGB_HL8_SWAP,
+            v_W0_YRGB_8_SWAP(0) | v_W0_YRGB_16_SWAP(0) | v_W0_YRGB_R_SHIFT_SWAP(0) | v_W0_565_RB_SWAP(1) | v_W0_YRGB_M8_SWAP(0) | v_W0_CBR_8_SWAP(0) | v_W0_YRGB_HL8_SWAP(0) );
+        break;
+   
+    case 4:
+        LcdMskReg(inf, SWAP_CTRL, m_W0_YRGB_8_SWAP | m_W0_YRGB_16_SWAP | m_W0_YRGB_R_SHIFT_SWAP | m_W0_565_RB_SWAP | m_W0_YRGB_M8_SWAP | m_W0_CBR_8_SWAP | m_W0_YRGB_HL8_SWAP,
+            v_W0_YRGB_8_SWAP(0) | v_W0_YRGB_16_SWAP(0) | v_W0_YRGB_R_SHIFT_SWAP(0) | v_W0_565_RB_SWAP(0) | 
+            v_W0_YRGB_M8_SWAP((var->rotate==0)) | v_W0_CBR_8_SWAP(0) | v_W0_YRGB_HL8_SWAP(var->rotate!=0));
+        break;
+    default:
+        LcdMskReg(inf, SWAP_CTRL, m_W0_YRGB_8_SWAP | m_W0_YRGB_16_SWAP | m_W0_YRGB_R_SHIFT_SWAP | m_W0_565_RB_SWAP | m_W0_YRGB_M8_SWAP | m_W0_CBR_8_SWAP | m_W0_YRGB_HL8_SWAP,
+            v_W0_YRGB_8_SWAP(0) | v_W0_YRGB_16_SWAP(0) | v_W0_YRGB_R_SHIFT_SWAP(0) | v_W0_565_RB_SWAP(0) | v_W0_YRGB_M8_SWAP(0) | v_W0_CBR_8_SWAP(0)| v_W0_YRGB_HL8_SWAP(0) );
+    }
+
+    LcdWrReg(inf, REG_CFG_DONE, 0x01);
+
+    return 0;
+}
+
+static int win0fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+    struct rk2818fb_inf *inf = dev_get_drvdata(info->device);
+    struct fb_var_screeninfo *var0 = &info->var;
+    struct fb_fix_screeninfo *fix0 = &info->fix;
+    struct win0_par *par = info->par;
+    u32 y_offset=0, uv_offset=0, y_addr=0, uv_addr=0;
+
+    fbprintk(">>>>>> %s : %s\n", __FILE__, __FUNCTION__);
+
+       CHK_SUSPEND(inf);
+
+    switch(var0->nonstd&0xff)
+    {
+    case 0: // rgb
+        switch(var0->bits_per_pixel)
+        {
+        case 16:    // rgb565
+            var->xoffset = (var->xoffset) & (~0x1);
+            y_offset = (var->yoffset*var0->xres_virtual + var->xoffset)*2;
+            break;
+        default:    // rgb888
+            y_offset = (var->yoffset*var0->xres_virtual + var->xoffset)*4;
+            break;
+        }
+        break;
+    case 1: // yuv422
+        var->xoffset = (var->xoffset) & (~0x3);
+        y_offset = var->yoffset*var0->xres_virtual + var->xoffset;
+        uv_offset = var->yoffset*var0->xres_virtual + var->xoffset;
+        break;
+    case 2: // yuv4200
+        var->xoffset = (var->xoffset) & (~0x3);
+        var->yoffset = (var->yoffset) & (~0x1);
+        y_offset = var->yoffset*var0->xres_virtual + var->xoffset;
+        uv_offset = (var->yoffset/2)*var0->xres_virtual + var->xoffset;
+        break;
+    case 3: // yuv4201
+        var->xoffset = (var->xoffset) & (~0x3);
+        var->yoffset = (var->yoffset) & (~0x1);
+        y_offset = (var->yoffset/2)*2*var0->xres_virtual + (var->xoffset)*2;
+        uv_offset = (var->yoffset/2)*var0->xres_virtual + var->xoffset;
+        break;
+    case 4: // yuv420m
+        var->xoffset = (var->xoffset) & (~0x7);
+        var->yoffset = (var->yoffset) & (~0x1);
+        y_offset = (var->yoffset/2)*3*var0->xres_virtual + (var->xoffset)*3;
+        break;
+    case 5: // yuv444
+        var->xoffset = (var->xoffset) & (~0x3);
+        y_offset = var->yoffset*var0->xres_virtual + var->xoffset;
+        uv_offset = var->yoffset*2*var0->xres_virtual + var->xoffset*2;
+        break;
+    default:
+        return -EINVAL;
+    }
+
+    par->y_offset = y_offset;
+    par->uv_offset = uv_offset;
+
+    y_addr = fix0->smem_start + y_offset;
+    uv_addr = fix0->mmio_start + uv_offset;
+
+    LcdWrReg(inf, WIN0_YRGB_MST, y_addr);
+    LcdWrReg(inf, WIN0_CBR_MST, uv_addr);
+    LcdWrReg(inf, REG_CFG_DONE, 0x01);
+
+    // enable win0 after the win0 addr is seted
+       par->par_seted = 1;
+       LcdMskReg(inf, SYS_CONFIG, m_W0_ENABLE, v_W0_ENABLE((1==par->addr_seted)?(1):(0)));
+       mcu_refresh(inf);
+
+    return 0;
+}
+
+int win0fb_open(struct fb_info *info, int user)
+{
+    struct win0_par *par = info->par;
+
+    fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__);
+
+    par->par_seted = 0;
+    par->addr_seted = 0;
+
+    if(par->refcount) {
+        printk(">>>>>> win0fb has opened! \n");
+        return -EACCES;
+    } else {
+        par->refcount++;
+        return 0;
+    }
+}
+
+int win0fb_release(struct fb_info *info, int user)
+{
+    struct win0_par *par = info->par;
+       struct fb_var_screeninfo *var0 = &info->var;
+
+    fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__);
+
+    if(par->refcount) {
+        par->refcount--;
+
+        win0fb_blank(FB_BLANK_POWERDOWN, info);
+        // wait for lcdc stop access memory
+        msleep(50);
+
+        // unmap memory
+        if (info->screen_base) {
+            printk(">>>>>> win0fb unmap memory(%d)! \n", info->fix.smem_len);
+           dma_free_writecombine(NULL, PAGE_ALIGN(info->fix.smem_len),info->screen_base, info->fix.smem_start);
+           info->screen_base = 0;
+           info->fix.smem_start = 0;
+           info->fix.smem_len = 0;
+        }
+
+               // clean the var param
+               memset(var0, 0, sizeof(struct fb_var_screeninfo));
+    }
+
+    return 0;
+}
+
+static int win0fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
+{
+    struct rk2818fb_inf *inf = dev_get_drvdata(info->device);
+    struct win0_par *par = info->par;
+    void __user *argp = (void __user *)arg;
+
+       fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__);
+
+       CHK_SUSPEND(inf);
+
+    switch(cmd)
+    {
+    case FB1_IOCTL_GET_PANEL_SIZE:    //get panel size
+        {
+            u32 panel_size[2];
+            if(IsMcuLandscape()) {
+                panel_size[0] = inf->cur_screen->y_res;
+                panel_size[1] = inf->cur_screen->x_res;
+            } else {
+                panel_size[0] = inf->cur_screen->x_res;
+                panel_size[1] = inf->cur_screen->y_res;
+            }
+            if(copy_to_user(argp, panel_size, 8))  return -EFAULT;
+        }
+        break;
+
+    case FB1_IOCTL_SET_YUV_ADDR:    //set y&uv address to register direct
+        {
+            u32 yuv_phy[2];
+            if (copy_from_user(yuv_phy, argp, 8))
+                           return -EFAULT;
+
+            yuv_phy[0] += par->y_offset;
+            yuv_phy[1] += par->uv_offset;
+
+            //printk("new y_addr=%08x, new uv_addr=%08x \n", yuv_phy[0], yuv_phy[1]);
+            LcdWrReg(inf, WIN0_YRGB_MST, yuv_phy[0]);
+            LcdWrReg(inf, WIN0_CBR_MST, yuv_phy[1]);
+            LcdWrReg(inf, REG_CFG_DONE, 0x01);
+
+            // enable win0 after the win0 par is seted
+            par->addr_seted = 1;
+            if(par->par_seted) { 
+               LcdMskReg(inf, SYS_CONFIG, m_W0_ENABLE, v_W0_ENABLE(1));
+                mcu_refresh(inf);
+            }
+        }
+        break;
+
+    case FB1_TOCTL_SET_MCU_DIR:    //change MCU panel scan direction
+        {
+            fbprintk(">>>>>> change MCU panel scan direction(%d) \n", (int)arg);
+
+            if(SCREEN_MCU!=inf->cur_screen->type)   return -1;
+
+            switch(arg)
+            {
+            case 0:
+            case 90:
+            case 180:
+            case 270:
+                {
+                    if(inf->cur_screen->scandir) {
+                        inf->mcu_stopflush = 1;
+                        inf->mcu_needflush = 0;
+                        inf->mcu_status = FMK_IDLE;
+                        while(!LcdReadBit(inf, MCU_TIMING_CTRL, m_MCU_HOLD_STATUS)) {
+                            msleep(10);
+                        }
+                        msleep(10);
+                        while(!LcdReadBit(inf, MCU_TIMING_CTRL, m_MCU_HOLD_STATUS)) {
+                            msleep(10);
+                        }
+                        msleep(10);
+
+                        inf->cur_screen->scandir(arg);
+                    }
+                    inf->mcu_scandir = arg;
+                    load_screen(info, 0);
+                    msleep(10);
+                    inf->mcu_stopflush = 0;
+                    win1fb_set_par(inf->win1fb);
+                }
+                break;
+
+            default:
+                return -1;
+            }
+        }
+        break;
+    default:
+        break;
+    }
+    return 0;
+}
+
+static struct fb_ops win0fb_ops = {
+       .owner          = THIS_MODULE,
+       .fb_open    = win0fb_open,
+       .fb_release = win0fb_release,
+       .fb_check_var   = win0fb_check_var,
+       .fb_set_par     = win0fb_set_par,
+       .fb_blank       = win0fb_blank,
+    .fb_pan_display = win0fb_pan_display,
+    .fb_ioctl = win0fb_ioctl,
+       .fb_setcolreg   = fb_setcolreg,
+       .fb_fillrect    = cfb_fillrect,
+       .fb_copyarea    = cfb_copyarea,
+       .fb_imageblit   = cfb_imageblit,        
+       .fb_rotate      = NULL,//win0fb_rotate,
+};
+
+static int win1fb_blank(int blank_mode, struct fb_info *info)
+{
+    struct rk2818fb_inf *inf = dev_get_drvdata(info->device);
+    struct win1_par *par = info->par;
+
+    fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__);
+
+       CHK_SUSPEND(inf);
+
+       switch(blank_mode)
+    {
+    case FB_BLANK_UNBLANK:
+        LcdMskReg(inf, SYS_CONFIG, m_W1_ENABLE, v_W1_ENABLE(1));
+        par->fmktmp.enable = 1;
+        par->fmktmp.completed = 1;
+        break;
+    default:
+        LcdMskReg(inf, SYS_CONFIG, m_W1_ENABLE, v_W1_ENABLE(0));
+        par->fmktmp.enable = 0;
+        par->fmktmp.completed = 1;
+        break;
+    }
+    LcdWrReg(inf, REG_CFG_DONE, 0x01);
+
+       mcu_refresh(inf);
+    return 0;
+}
+
+static int win1fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+    struct rk2818fb_inf *inf = dev_get_drvdata(info->device);
+    struct rk28fb_screen *screen = inf->cur_screen;
+    u32 ScaleY = 0x1000;
+    u16 xpos = (var->nonstd>>8) & 0xfff;
+    u16 ypos = (var->nonstd>>20) & 0xfff;
+    u16 xlcd = screen->x_res;
+    u16 ylcd = screen->y_res;
+    u8 trspmode = (var->grayscale>>8) & 0xff;
+    u8 trspval = (var->grayscale) & 0xff;
+
+    fbprintk(">>>>>> %s : %s\n", __FILE__, __FUNCTION__);
+
+       CHK_SUSPEND(inf);
+
+#if (0==WIN1_USE_DOUBLE_BUF)
+    if(var->yres_virtual>ylcd)
+        var->yres_virtual = ylcd;
+#endif
+
+    if( 0==var->xres_virtual || 0==var->yres_virtual ||
+        0==var->xres || 0==var->yres || var->xres<16 ||
+        trspmode>5 || trspval>16 ||
+        ((16!=var->bits_per_pixel)&&(32!=var->bits_per_pixel)) )
+    {
+        printk(">>>>>> win1fb_check_var fail 1!!! \n");
+        printk(">>>>>> 0==%d || 0==%d ", var->xres_virtual,var->yres_virtual);
+        printk("0==%d || 0==%d || %d<16 || ", var->xres,var->yres,var->xres<16);
+        printk("%d>5 || %d>16 \n", trspmode,trspval);
+        printk("bits_per_pixel=%d \n", var->bits_per_pixel);
+        return -EINVAL;
+    }
+
+    if( (var->xoffset+var->xres)>var->xres_virtual ||
+        (var->yoffset+var->yres)>var->yres_virtual ||
+        (xpos+var->xres)>xlcd || (ypos+var->yres)>ylcd )
+    {
+        printk(">>>>>> win1fb_check_var fail 2!!! \n");
+        printk(">>>>>> (%d+%d)>%d || ", var->xoffset,var->xres,var->xres_virtual);
+        printk("(%d+%d)>%d || ", var->yoffset,var->yres,var->yres_virtual);
+        printk("(%d+%d)>%d || (%d+%d)>%d \n", xpos,var->xres,xlcd,ypos,var->yres,ylcd);
+        return -EINVAL;
+    }
+
+    switch(var->bits_per_pixel)
+    {
+    case 16:    // rgb565
+        var->xres_virtual = (var->xres_virtual + 0x1) & (~0x1);
+        var->xres = (var->xres + 0x1) & (~0x1);
+        var->xoffset = (var->xoffset) & (~0x1);
+        break;
+    default:    // rgb888
+        var->bits_per_pixel = 32;
+        break;
+    }
+    
+  //  ScaleY = CalScaleW1(var->yres, ysize);
+    if((ScaleY>0x8000) ||(ScaleY<0x200))
+    {
+        return (-EINVAL);        // multiple of scale down or scale up can't exceed 8
+    }   
+    return 0;
+}
+
+static int win1fb_set_par(struct fb_info *info)
+{
+    struct rk2818fb_inf *inf = dev_get_drvdata(info->device);
+    struct fb_var_screeninfo *var = &info->var;
+    struct fb_fix_screeninfo *fix = &info->fix;
+    struct rk28fb_screen *screen = inf->cur_screen;
+    struct win1_par *par = info->par;
+
+    u8 format = 0;
+    dma_addr_t map_dma;
+    u32 offset=0, addr=0, map_size=0, smem_len=0;
+    u16 xpos = (var->nonstd>>8) & 0xfff;
+    u16 ypos = (var->nonstd>>20) & 0xfff;
+    u16 xres = var->xres, yres = var->yres, xres_virtual = var->xres_virtual;
+    // u8 trspmode = TRSP_FMREG; //(var->grayscale>>8) & 0xff;
+    // u8 trspmode = TRSP_CLOSE;    // ²»Ê¹ÓÃÓ²¼þµÄ°ë͸²Ù×÷.
+    u8 trspmode = TRSP_CLOSE;        // ½«Ö¸¶¨µÄ ÏñËØ value (ȱʡÊÇ ºÚÉ«(0, 0, 0) ), ÉèÖÃΪ È«Í¸.
+    u8 trspval = 1;    //(var->grayscale) & 0xff;
+    u32 i;
+
+    //the below code is not correct, make we can't see alpha picture.
+    //u8 trspmode = (var->grayscale>>8) & 0xff;
+    //u8 trspval = (var->grayscale) & 0xff;
+
+    fbprintk(">>>>>> %s : %s\n", __FILE__, __FUNCTION__);
+
+       CHK_SUSPEND(inf);
+
+    switch(var->bits_per_pixel)
+    {
+    case 16:    // rgb565
+        format = 1;
+        fix->line_length = 2 * var->xres_virtual;
+        offset = (var->yoffset*var->xres_virtual + var->xoffset)*2;
+        break;
+    case 32:    // rgb888
+    default:
+        format = 0;
+        fix->line_length = 4 * var->xres_virtual;
+        offset = (var->yoffset*var->xres_virtual + var->xoffset)*4;
+        break;
+    }
+
+    smem_len = fix->line_length * var->yres_virtual;
+    map_size = PAGE_ALIGN(smem_len);
+
+#if WIN1_USE_DOUBLE_BUF
+    if( var->yres_virtual == 2*screen->y_res ) {
+        inf->mcu_usetimer = 0;
+    }
+    if(0==fix->smem_len) {
+        smem_len = smem_len*2;
+        map_size = PAGE_ALIGN(smem_len);
+        fbprintk(">>>>>> first alloc, alloc double!!! \n ");
+    }
+#endif
+
+#if WIN1_USE_DOUBLE_BUF
+    if (smem_len > fix->smem_len)     // buffer need realloc
+#else
+    if (smem_len != fix->smem_len)     // buffer need realloc
+#endif
+    {
+        fbprintk(">>>>>> win1 buffer size is change(%d->%d)! remap memory!\n",fix->smem_len, smem_len);
+        fbprintk(">>>>>> smem_len %d = %d * %d \n", smem_len, fix->line_length, var->yres_virtual);
+        fbprintk(">>>>>> map_size = %d\n", map_size);
+        LcdMskReg(inf, SYS_CONFIG, m_W1_ENABLE, v_W1_ENABLE(0));
+        LcdWrReg(inf, REG_CFG_DONE, 0x01);
+        msleep(50);
+        if (info->screen_base) {
+            printk(">>>>>> win1fb unmap memory(%d)! \n", info->fix.smem_len);
+               dma_free_writecombine(NULL, PAGE_ALIGN(info->fix.smem_len), info->screen_base, info->fix.smem_start);
+               info->screen_base = 0;
+               fix->smem_start = 0;
+               fix->smem_len = 0;
+        }
+
+        info->screen_base = dma_alloc_writecombine(NULL, map_size, &map_dma, GFP_KERNEL);
+        if(!info->screen_base) {
+            printk(">>>>>> win1fb dma_alloc_writecombine fail!\n");
+            return -ENOMEM;
+        }
+        memset(info->screen_base, 0, map_size);
+        fix->smem_start = map_dma;
+        fix->smem_len = smem_len;
+        fbprintk(">>>>>> alloc succ, mem=%08x, len=%d!\n", (u32)fix->smem_start, fix->smem_len);     
+    }
+
+    addr = fix->smem_start + offset;
+
+    if(TRSP_FMREGEX==trspmode)     trspmode = TRSP_FMREG;
+    if(TRSP_FMRAMEX==trspmode)     trspmode = TRSP_FMRAM;
+
+    LcdMskReg(inf, SYS_CONFIG, m_W1_ENABLE|m_W1_FORMAT, v_W1_ENABLE(1)|v_W1_FORMAT(format));  
+
+    xpos += (screen->left_margin + screen->hsync_len);
+    ypos += (screen->upper_margin + screen->vsync_len);
+   
+    LcdWrReg(inf, WIN1_YRGB_MST, addr);
+    LcdWrReg(inf, WIN1_VIR_MST, fix->smem_start);
+    
+    LcdMskReg(inf, WIN1_DSP_ST, m_BIT11LO|m_BIT11HI, v_BIT11LO(xpos) | v_BIT11HI(ypos));
+    LcdMskReg(inf, WIN1_DSP_INFO, m_BIT11LO|m_BIT11HI, v_BIT11LO(xres) | v_BIT11HI(yres)); 
+
+    LcdMskReg(inf, WIN1_VIR, m_WORDLO | m_WORDHI , v_WORDLO(xres_virtual) | v_WORDHI(var->yres_virtual));
+    LcdMskReg(inf, WIN1_ACT_INFO, m_WORDLO | m_WORDHI, v_WORDLO(xres) | v_WORDHI(yres));
+
+    LcdMskReg(inf, BLEND_CTRL, m_W1_BLEND_EN | m_W1_BLEND_FACTOR_SELECT | m_W1_BLEND_FACTOR,
+        v_W1_BLEND_EN((TRSP_FMREG==trspmode) || (TRSP_MASK==trspmode)) | 
+        v_W1_BLEND_FACTOR_SELECT(TRSP_FMRAM==trspmode) | v_W1_BLEND_FACTOR(trspval));  //͸Ã÷¶È  
+        
+    if(1==format) //rgb565
+    {
+        LcdMskReg(inf, SWAP_CTRL, m_W1_8_SWAP | m_W1_16_SWAP | m_W1_R_SHIFT_SWAP | m_W1_565_RB_SWAP,
+            v_W1_8_SWAP(0) | v_W1_16_SWAP(0) | v_W1_R_SHIFT_SWAP(0) | v_W1_565_RB_SWAP(0) );
+    } 
+    else 
+    {
+     LcdMskReg(inf, SWAP_CTRL, m_W1_8_SWAP | m_W1_16_SWAP | m_W1_R_SHIFT_SWAP | m_W1_565_RB_SWAP,
+            v_W1_8_SWAP(0) | v_W1_16_SWAP(0) | v_W1_R_SHIFT_SWAP(0) | v_W1_565_RB_SWAP(0) );
+    }
+
+       LcdWrReg(inf, REG_CFG_DONE, 0x01);
+
+    return 0;    
+}
+
+static int win1fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+    struct rk2818fb_inf *inf = dev_get_drvdata(info->device);
+    struct rk28fb_screen *screen = inf->cur_screen;
+    struct fb_var_screeninfo *var1 = &info->var;
+    struct fb_fix_screeninfo *fix1 = &info->fix;
+    struct win1_par *par = info->par;
+    u32 offset = 0, addr = 0;
+    u32 i=0;
+    
+       fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__);
+
+       CHK_SUSPEND(inf);
+
+    switch(var1->bits_per_pixel)
+    {
+    case 16:    // rgb565
+        var->xoffset = (var->xoffset) & (~0x1);
+        offset = (var->yoffset*var1->xres_virtual + var->xoffset)*2;
+        break;
+    case 32:    // rgb888
+        offset = (var->yoffset*var1->xres_virtual + var->xoffset)*4;
+        break;
+    default:
+        return -EINVAL;
+    }
+    
+    addr = fix1->smem_start + offset;
+    fbprintk("info->screen_base = %8x ; fix1->smem_len = %d , addr = %8x\n",info->screen_base, fix1->smem_len, addr);
+
+    LcdWrReg(inf, WIN1_YRGB_MST, addr);
+    LcdWrReg(inf, REG_CFG_DONE, 0x01);
+
+       mcu_refresh(inf);
+
+    // flush end when wq_condition=1 in mcu panel, but not in rgb panel
+    if(SCREEN_MCU == inf->cur_screen->type) {
+        wait_event_interruptible_timeout(wq, wq_condition, HZ/20);
+        wq_condition = 0;
+    } else {
+        wq_condition = 0;
+        wait_event_interruptible_timeout(wq, wq_condition, HZ/20);
+    }
+
+    return 0;
+}
+
+
+static int win1fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
+{
+    struct rk2818fb_inf *inf = dev_get_drvdata(info->device);
+    struct rk2818_fb_mach_info *mach_info = info->device->platform_data;
+    unsigned display_on;    
+    int display_on_pol;
+
+       fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__);
+
+       CHK_SUSPEND(inf);
+
+    switch(cmd)
+    {
+    case FB0_IOCTL_STOP_TIMER_FLUSH:    //stop timer flush mcu panel after android is runing
+        if(1==arg)
+        {
+            inf->mcu_usetimer = 0;
+        }
+        break;
+
+    case FB0_IOCTL_SET_PANEL:
+        if(arg>7)   return -1;
+
+        /* Black out, because some display device need clock to standby */
+        //LcdMskReg(inf, DSP_CTRL_REG1, m_BLACK_OUT, v_BLACK_OUT(1));
+        LcdMskReg(inf, SYS_CONFIG, m_W0_ENABLE, v_W0_ENABLE(0));
+        LcdMskReg(inf, SYS_CONFIG, m_W1_ENABLE, v_W1_ENABLE(0));
+        LcdMskReg(inf, DSP_CTRL1, m_BLACK_MODE,  v_BLACK_MODE(1));          
+        LcdWrReg(inf, REG_CFG_DONE, 0x01);
+        if(inf->cur_screen)
+        {
+            if(inf->cur_screen->standby)    inf->cur_screen->standby(1);
+            // operate the display_on pin to power down the lcd
+            if(SCREEN_RGB==inf->cur_screen->type || SCREEN_MCU==inf->cur_screen->type) 
+            {
+                if(mach_info && mach_info->gpio && mach_info->gpio->display_on)
+                {
+                    display_on = mach_info->gpio->display_on&0xffff;    
+                    display_on_pol = (mach_info->gpio->display_on>>16)&0xffff;                    
+                    gpio_direction_output(display_on, 0);
+                       gpio_set_value(display_on, !display_on_pol);
+                }
+            }
+        }
+
+        /* Load the new device's param */
+        switch(arg)
+        {
+        case 0: inf->cur_screen = &inf->lcd_info;   break;  //lcd
+        case 1: inf->cur_screen = &inf->tv_info[0]; break;  //tv ntsc cvbs
+        case 2: inf->cur_screen = &inf->tv_info[1]; break;  //tv pal cvbs
+        case 3: inf->cur_screen = &inf->tv_info[2]; break;  //tv 480 ypbpr
+        case 4: inf->cur_screen = &inf->tv_info[3]; break;  //tv 576 ypbpr
+        case 5: inf->cur_screen = &inf->tv_info[4]; break;  //tv 720 ypbpr
+        case 6: inf->cur_screen = &inf->hdmi_info[0];  break;  //hdmi 576
+        case 7: inf->cur_screen = &inf->hdmi_info[1];  break;  //hdmi 720
+        default: break;
+        }
+        load_screen(info, 1);
+               mcu_refresh(inf);
+        break;
+    default:
+        break;
+    }
+    return 0;
+}
+
+
+static struct fb_ops win1fb_ops = {
+       .owner          = THIS_MODULE,
+       .fb_check_var   = win1fb_check_var,
+       .fb_set_par = win1fb_set_par,
+       .fb_blank   = win1fb_blank,
+       .fb_pan_display = win1fb_pan_display,
+    .fb_ioctl = win1fb_ioctl,
+       .fb_setcolreg   = fb_setcolreg,
+       .fb_fillrect    = cfb_fillrect,
+       .fb_copyarea    = cfb_copyarea,
+       .fb_imageblit   = cfb_imageblit,
+       .fb_cursor      = NULL,//fb_set_cursor,
+};
+
+
+static irqreturn_t rk2818fb_irq(int irq, void *dev_id)
+{
+       struct platform_device *pdev = (struct platform_device*)dev_id;
+    struct rk2818fb_inf *inf = platform_get_drvdata(pdev);
+    if(!inf)
+        return IRQ_HANDLED;
+
+       //fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__);
+
+    LcdMskReg(inf, INT_STATUS, m_FRM_STARTCLEAR, v_FRM_STARTCLEAR(1));
+
+       if(SCREEN_MCU == inf->cur_screen->type)
+       {
+        inf->mcu_isrcnt = !inf->mcu_isrcnt;
+        if(inf->mcu_isrcnt)
+            return IRQ_HANDLED;
+
+        if(IsMcuUseFmk())
+        {
+            if(inf->mcu_needflush) {
+                if(FMK_IDLE==inf->mcu_fmkstate || FMK_ENDING==inf->mcu_fmkstate) {
+                    inf->mcu_fmkstate = FMK_INT;
+                    inf->mcu_needflush = 0;
+                    fbprintk2("A ");
+                } else {
+                    return IRQ_HANDLED;
+                }
+            } else {
+                if(FMK_ENDING==inf->mcu_fmkstate) {
+                    if(inf->cur_screen->refresh)
+                        inf->cur_screen->refresh(REFRESH_END);
+                    inf->mcu_fmkstate = FMK_IDLE;
+                } else {
+                    return IRQ_HANDLED;
+                }
+            }
+        }
+        else
+        {
+            if(inf->mcu_needflush) {
+                if(inf->cur_screen->refresh)
+                    inf->cur_screen->refresh(REFRESH_PRE);
+                inf->mcu_needflush = 0;
+                LcdSetBit(inf, MCU_TIMING_CTRL, m_MCU_HOLDMODE_FRAME_ST);               
+            } else {
+                if(inf->cur_screen->refresh)
+                    inf->cur_screen->refresh(REFRESH_END);
+            }
+        }
+       }
+
+       wq_condition = 1;
+       wake_up_interruptible(&wq);
+
+       return IRQ_HANDLED;
+}
+
+
+static irqreturn_t rk2818fb_irqfmk(int irq, void *dev_id)
+{
+       struct platform_device *pdev = (struct platform_device*)dev_id;
+    struct rk2818fb_inf *inf = platform_get_drvdata(pdev);
+    struct rk28fb_screen *screen;
+    struct win0_par *w0par;
+    struct win1_par *w1par;
+    u16 hact_st = 0;
+    static u8 leap_cnt = 0;
+    u16 tmp = 1;
+
+    if(!inf)    return IRQ_HANDLED;
+
+    screen = inf->cur_screen;
+    w0par = inf->win0fb->par;
+    w1par = inf->win1fb->par;
+
+    if(0==screen->mcu_usefmk) {
+        inf->mcu_fmkstate = FMK_IDLE;
+        return IRQ_HANDLED;
+    }
+
+    hact_st = LcdReadBit(inf, DSP_HACT_ST_END, m_BIT11HI);
+
+    switch(inf->mcu_fmkstate)
+    {
+    case FMK_INT: // ¿ª¶¨Ê±Æ÷(FMKµ½)
+        if(0==irq)    return IRQ_HANDLED;
+        if(screen->mcu_usefmk && IsMcuLandscape())
+        {
+            if(leap_cnt)   { leap_cnt--; return IRQ_HANDLED; }    //ÊúÆÁתºáÆÁ¶ªµô2¸öÖжÏÒÔͬ²½
+            if(w0par->fmktmp.completed)   { w0par->fmk = w0par->fmktmp;  w0par->fmktmp.completed = 0; }
+            if(w1par->fmktmp.completed)   { w1par->fmk = w1par->fmktmp;  w1par->fmktmp.completed = 0; }
+            inf->mcu_fmkstate = FMK_PRELEFT;
+        } else if ( (2==screen->mcu_usefmk) && (!IsMcuLandscape()) ) {
+            leap_cnt = 2;
+            inf->mcu_fmkstate = FMK_PREUP;
+        } else {
+            leap_cnt = 0;
+            inf->mcu_fmkstate = FMK_IDLE;
+            break;
+        }
+#if FMK_USE_HARDTIMER
+      //  rockchip_usertimer_start(500000/screen->mcu_frmrate, rk28fb_dohardtimer);
+#else
+    //    hrtimer_start(&inf->htimer,ktime_set(0,(450000000/screen->mcu_frmrate)),HRTIMER_MODE_REL);
+#endif
+        break;
+
+    case FMK_PRELEFT: // ËÍ×ó°ëÆÁ(¶¨Ê±Æ÷µ½)
+        if(0!=irq)      return IRQ_HANDLED;
+        if(!LcdReadBit(inf, MCU_TIMING_CTRL, m_MCU_HOLD_STATUS)) {
+            inf->mcu_fmkstate = FMK_IDLE;
+            printk("L failed! \n");
+            return IRQ_HANDLED;
+        }
+        if (screen->disparea)    screen->disparea(0);
+
+        if (w0par->fmk.enable && w0par->fmk.addr_y[0]) 
+        {
+                    LcdMskReg(inf, SYS_CONFIG, m_W0_ENABLE|m_W0_FORMAT,  v_W0_ENABLE(1)|v_W0_FORMAT(w0par->fmk.format));
+                    LcdWrReg(inf, WIN0_YRGB_MST, w0par->fmk.addr_y[0]);
+                    LcdWrReg(inf, WIN0_CBR_MST, w0par->fmk.addr_uv[0]);
+                    LcdMskReg(inf, WIN0_ACT_INFO, m_WORDLO, v_WORDLO(w0par->fmk.act_w[0]));
+                    LcdMskReg(inf, WIN0_DSP_ST, m_BIT11LO, v_BIT11LO(w0par->fmk.win_stx[0]+hact_st));
+                    LcdMskReg(inf, WIN0_DSP_INFO, m_BIT11LO,  v_BIT11LO(w0par->fmk.win_w[0]));
+                    w0par->fmk.addr_y[1] = w0par->fmk.addr_y[0] + w0par->fmk.addr_y2offset;
+                     w0par->fmk.addr_uv[1] = w0par->fmk.addr_uv[0] + w0par->fmk.addr_uv2offset;
+        }
+        else
+        {
+            LcdMskReg(inf, SYS_CONFIG, m_W0_ENABLE,  v_W0_ENABLE(0));
+        }
+
+        if (w1par->fmk.enable && w1par->fmk.addr[0])   // Win1
+        {
+            LcdMskReg(inf, SYS_CONFIG, m_W1_ENABLE, v_W1_ENABLE(1));
+            LcdWrReg(inf, WIN1_YRGB_MST, w1par->fmk.addr[0]);
+            LcdMskReg(inf, WIN1_DSP_ST, m_BIT11LO, v_BIT11LO(w1par->fmk.win_stx[0]+hact_st));
+            LcdMskReg(inf, WIN1_ACT_INFO, m_BIT11LO, v_BIT11LO(w1par->fmk.act_w[0]));
+            w1par->fmk.addr[1] = w1par->fmk.addr[0] + w1par->fmk.addr2_offset;
+        }
+        else           
+        {
+            LcdMskReg(inf, SYS_CONFIG, m_W1_ENABLE, v_W1_ENABLE(0));
+        }
+
+        LcdSetBit(inf,MCU_TIMING_CTRL, m_MCU_HOLDMODE_FRAME_ST);
+        LcdWrReg(inf, REG_CFG_DONE, 0x01);
+        inf->mcu_fmkstate = FMK_LEFT;
+        fbprintk2("L ");
+        break;
+
+    case FMK_LEFT: // ËÍÓÒ°ëÆÁ(FMKµ½)
+        if(0==irq)    return IRQ_HANDLED;
+        while(!LcdReadBit(inf, MCU_TIMING_CTRL, m_MCU_HOLD_STATUS)) {
+            udelay(25);
+            if(tmp)  printk("X ");
+            tmp = 0;
+        }
+        if(screen->disparea)    screen->disparea(1);
+
+        if (w0par->fmk.enable && w0par->fmk.addr_y[1]) // win0
+        {
+            LcdMskReg(inf, SYS_CONFIG, m_W0_ENABLE|m_W0_FORMAT,  v_W0_ENABLE(1)|v_W0_FORMAT(w0par->fmk.format));
+            LcdWrReg(inf, WIN0_YRGB_MST, w0par->fmk.addr_y[1]);
+            LcdWrReg(inf, WIN0_CBR_MST, w0par->fmk.addr_uv[1]);
+            LcdMskReg(inf, WIN0_ACT_INFO, m_WORDLO, v_WORDLO(w0par->fmk.act_w[1]));
+            LcdMskReg(inf, WIN0_DSP_ST, m_BIT11LO, v_BIT11LO(w0par->fmk.win_stx[1]+hact_st));
+            LcdMskReg(inf, WIN0_DSP_INFO, m_BIT11LO,  v_BIT11LO(w0par->fmk.win_w[1]));
+        }
+        else 
+        {
+            LcdMskReg(inf, SYS_CONFIG, m_W0_ENABLE, v_W0_ENABLE(0));
+        }
+
+        if (w1par->fmk.enable && w1par->fmk.addr[1])   // win1
+        {
+            LcdMskReg(inf, SYS_CONFIG, m_W1_ENABLE, v_W1_ENABLE(1));
+            LcdWrReg(inf, WIN1_YRGB_MST, w1par->fmk.addr[1]);
+            LcdMskReg(inf, WIN1_DSP_ST, m_BIT11LO, v_BIT11LO(w1par->fmk.win_stx[1]+hact_st));
+            LcdMskReg(inf, WIN1_ACT_INFO, m_BIT11LO, v_BIT11LO(w1par->fmk.act_w[1]));
+        }
+        else 
+        {
+            LcdMskReg(inf, SYS_CONFIG, m_W1_ENABLE, v_W1_ENABLE(0));
+        }
+
+        inf->mcu_isrcnt = 0;
+        inf->mcu_fmkstate = FMK_ENDING;
+        LcdSetBit(inf, MCU_TIMING_CTRL, m_MCU_HOLDMODE_FRAME_ST);       
+        LcdWrReg(inf, REG_CFG_DONE, 0x01);
+        fbprintk2("R ");
+        break;
+
+    case FMK_PREUP:     // ËÍÉÏ°ëÆÁ(¶¨Ê±Æ÷µ½)
+        if(0!=irq)      return IRQ_HANDLED;
+        if(screen->disparea)    screen->disparea(2);
+        inf->mcu_isrcnt = 0;
+        inf->mcu_fmkstate = FMK_UP;
+        LcdSetBit(inf, MCU_TIMING_CTRL, m_MCU_HOLDMODE_FRAME_ST);
+        LcdWrReg(inf, REG_CFG_DONE, 0x01);
+        fbprintk2("U ");
+        break;
+
+    case FMK_UP:        // ËÍÏ°ëÆÁ(FMKµ½)
+        if(0==irq)    return IRQ_HANDLED;
+        fbprintk2("D ");
+        inf->mcu_fmkstate = FMK_ENDING;
+        break;
+
+    case FMK_ENDING:
+    default:
+        inf->mcu_fmkstate = FMK_IDLE;
+        break;
+    }
+
+       return IRQ_HANDLED;
+}
+
+static int __init rk2818fb_probe (struct platform_device *pdev)
+{
+    struct rk2818fb_inf *inf = NULL;
+    struct resource *res = NULL;
+    struct resource *mem = NULL;
+    struct rk2818_fb_mach_info *mach_info = NULL;
+    struct rk28fb_screen *screen = NULL;
+       int irq = 0;
+    int ret = 0;
+
+//------------------back light-----------------------
+    rk2818_mux_api_set(GPIOF2_APWM0_SEL_NAME, 0);
+    ret = gpio_request(RK2818_PIN_PF2, NULL); 
+    if(ret != 0)
+    {
+        gpio_free(RK2818_PIN_PF2);
+        printk(KERN_ERR ">>>>>> back light gpio_request err \n ");
+        return 1;
+    }
+    gpio_direction_output(RK2818_PIN_PF2, 0);
+       gpio_set_value(RK2818_PIN_PF2, 0);
+
+//-----------------------------------------
+
+    fbprintk(">>>>>> %s : %s\n", __FILE__, __FUNCTION__);
+
+    /* Malloc rk2818fb_inf and set it to pdev for drvdata */
+    fbprintk(">> Malloc rk2818fb_inf and set it to pdev for drvdata \n");
+    inf = kmalloc(sizeof(struct rk2818fb_inf), GFP_KERNEL);
+    if(!inf) 
+    {
+        dev_err(&pdev->dev, ">> inf kmalloc fail!");
+        ret = -ENOMEM;
+               goto release_drvdata;
+    }
+    fbprintk(">> rk2818fb_inf addr = 0x%x \n", inf);
+    memset(inf, 0, sizeof(struct rk2818fb_inf));
+       platform_set_drvdata(pdev, inf);
+
+    /* Fill screen info and set current screen */
+    fbprintk(">> Fill screen info and set current screen \n");
+    set_lcd_info(&inf->lcd_info);
+    set_tv_info(&inf->tv_info[0]);
+    set_hdmi_info(&inf->hdmi_info[0]);
+    inf->cur_screen = &inf->lcd_info;
+    screen = inf->cur_screen;
+    if(SCREEN_NULL==screen->type) 
+    {
+        dev_err(&pdev->dev, ">> Please select a display device! \n");
+        ret = -EINVAL;
+               goto release_drvdata;
+    }
+
+    /* get virtual basic address of lcdc register */
+    fbprintk(">> get virtual basic address of lcdc register \n");
+    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+    if (res == NULL) 
+    {
+        dev_err(&pdev->dev, "failed to get memory registers\n");
+        ret = -ENOENT;
+               goto release_drvdata;
+    }
+    inf->reg_phy_base = res->start;
+    inf->len = (res->end - res->start) + 1;
+    mem = request_mem_region(inf->reg_phy_base, inf->len, pdev->name);
+    if (mem == NULL) 
+    {
+        dev_err(&pdev->dev, "failed to get memory region\n");
+        ret = -ENOENT;
+               goto release_drvdata;
+    }
+    fbprintk("inf->reg_phy_base = 0x%08x, inf->len = %d \n", inf->reg_phy_base, inf->len);
+    inf->reg_vir_base = ioremap(inf->reg_phy_base, inf->len);
+    if (inf->reg_vir_base == NULL) 
+    {
+        dev_err(&pdev->dev, "ioremap() of registers failed\n");
+        ret = -ENXIO;
+               goto release_drvdata;
+    }  
+    inf->preg = (LCDC_REG*)inf->reg_vir_base;
+
+    /* Prepare win1 info */
+    fbprintk(">> Prepare win1 info \n");
+       inf->win1fb = framebuffer_alloc(sizeof(struct win1_par), &pdev->dev);
+    if(!inf->win1fb) 
+    {
+        dev_err(&pdev->dev, ">> win1fb framebuffer_alloc fail!");
+               inf->win1fb = NULL;
+        ret = -ENOMEM;
+               goto release_win1fb;
+    }
+
+    strcpy(inf->win1fb->fix.id, "win1fb");
+    inf->win1fb->fix.type        = FB_TYPE_PACKED_PIXELS;
+    inf->win1fb->fix.type_aux    = 0;
+    inf->win1fb->fix.xpanstep    = 1;
+    inf->win1fb->fix.ypanstep    = 1;
+    inf->win1fb->fix.ywrapstep   = 0;
+    inf->win1fb->fix.accel       = FB_ACCEL_NONE;
+    inf->win1fb->fix.visual      = FB_VISUAL_TRUECOLOR;
+    inf->win1fb->fix.smem_len    = 0;
+    inf->win1fb->fix.line_length = 0;
+    inf->win1fb->fix.smem_start  = 0;
+
+    inf->win1fb->var.xres = screen->x_res;
+    inf->win1fb->var.yres = screen->y_res;
+    inf->win1fb->var.bits_per_pixel = 16;
+    inf->win1fb->var.xres_virtual = screen->x_res;
+    inf->win1fb->var.yres_virtual = screen->y_res;
+    inf->win1fb->var.width = screen->x_res;
+    inf->win1fb->var.height = screen->y_res;
+    inf->win1fb->var.pixclock = screen->pixclock;
+    inf->win1fb->var.left_margin = screen->left_margin;
+    inf->win1fb->var.right_margin = screen->right_margin;
+    inf->win1fb->var.upper_margin = screen->upper_margin;
+    inf->win1fb->var.lower_margin = screen->lower_margin;
+    inf->win1fb->var.vsync_len = screen->vsync_len;
+    inf->win1fb->var.hsync_len = screen->hsync_len;
+    inf->win1fb->var.red    = def_rgb_16.red;
+    inf->win1fb->var.green  = def_rgb_16.green;
+    inf->win1fb->var.blue   = def_rgb_16.blue;
+    inf->win1fb->var.transp = def_rgb_16.transp;
+
+    inf->win1fb->var.nonstd      = 0;  //win1 format & ypos & xpos (ypos<<20 + xpos<<8 + format)
+    inf->win1fb->var.grayscale   = 0;  //win1 transprent mode & value(mode<<8 + value)
+    inf->win1fb->var.activate    = FB_ACTIVATE_NOW;
+    inf->win1fb->var.accel_flags = 0;
+    inf->win1fb->var.vmode       = FB_VMODE_NONINTERLACED;
+
+    inf->win1fb->fbops           = &win1fb_ops;
+    inf->win1fb->flags           = FBINFO_FLAG_DEFAULT;
+    inf->win1fb->pseudo_palette  = ((struct win1_par*)inf->win1fb->par)->pseudo_pal;
+    inf->win1fb->screen_base     = 0;
+
+    memset(inf->win1fb->par, 0, sizeof(struct win1_par));
+
+    /* Prepare win0 info */
+    fbprintk(">> Prepare win0 info \n");
+    inf->win0fb = framebuffer_alloc(sizeof(struct win0_par), &pdev->dev);
+    if(!inf->win0fb)
+    {
+        dev_err(&pdev->dev, ">> win0fb framebuffer_alloc fail!");
+               inf->win0fb = NULL;
+               ret = -ENOMEM;
+               goto release_win0fb;
+    }
+
+    strcpy(inf->win0fb->fix.id, "win0fb");
+       inf->win0fb->fix.type         = FB_TYPE_PACKED_PIXELS;
+       inf->win0fb->fix.type_aux    = 0;
+       inf->win0fb->fix.xpanstep    = 1;
+       inf->win0fb->fix.ypanstep    = 1;
+       inf->win0fb->fix.ywrapstep   = 0;
+       inf->win0fb->fix.accel       = FB_ACCEL_NONE;
+    inf->win0fb->fix.visual      = FB_VISUAL_TRUECOLOR;
+    inf->win0fb->fix.smem_len    = 0;
+    inf->win0fb->fix.line_length = 0;
+    inf->win0fb->fix.smem_start  = 0;
+
+    inf->win0fb->var.xres = screen->x_res;
+    inf->win0fb->var.yres = screen->y_res;
+    inf->win0fb->var.bits_per_pixel = 16;
+    inf->win0fb->var.xres_virtual = screen->x_res;
+    inf->win0fb->var.yres_virtual = screen->y_res;
+    inf->win0fb->var.width = screen->x_res;
+    inf->win0fb->var.height = screen->y_res;
+    inf->win0fb->var.pixclock = screen->pixclock;
+    inf->win0fb->var.left_margin = screen->left_margin;
+    inf->win0fb->var.right_margin = screen->right_margin;
+    inf->win0fb->var.upper_margin = screen->upper_margin;
+    inf->win0fb->var.lower_margin = screen->lower_margin;
+    inf->win0fb->var.vsync_len = screen->vsync_len;
+    inf->win0fb->var.hsync_len = screen->hsync_len;
+    inf->win0fb->var.red    = def_rgb_16.red;
+    inf->win0fb->var.green  = def_rgb_16.green;
+    inf->win0fb->var.blue   = def_rgb_16.blue;
+    inf->win0fb->var.transp = def_rgb_16.transp;
+
+    inf->win0fb->var.nonstd      = 0;  //win0 format & ypos & xpos (ypos<<20 + xpos<<8 + format)
+    inf->win0fb->var.grayscale   = ((inf->win0fb->var.yres<<20)&0xfff00000) + ((inf->win0fb->var.xres<<8)&0xfff00);//win0 xsize & ysize
+    inf->win0fb->var.activate    = FB_ACTIVATE_NOW;
+    inf->win0fb->var.accel_flags = 0;
+    inf->win0fb->var.vmode       = FB_VMODE_NONINTERLACED;
+
+    inf->win0fb->fbops           = &win0fb_ops;
+       inf->win0fb->flags                    = FBINFO_FLAG_DEFAULT;
+       inf->win0fb->pseudo_palette  = ((struct win0_par*)inf->win0fb->par)->pseudo_pal;
+       inf->win0fb->screen_base     = 0;
+
+    memset(inf->win0fb->par, 0, sizeof(struct win0_par));
+
+       /* Init all lcdc and lcd before register_framebuffer. */
+       /* because after register_framebuffer, the win1fb_check_par and winfb_set_par execute immediately */
+       fbprintk(">> Init all lcdc and lcd before register_framebuffer \n");
+    init_lcdc(inf->win1fb);
+    inf->clk = clk_get(&pdev->dev, "lcdc_hclk");
+    if (!inf->clk || IS_ERR(inf->clk)) 
+    {
+        printk(KERN_ERR "failed to get lcdc_hclk source\n");
+        ret = -ENOENT;
+        goto unregister_win1fb;
+    }
+    
+    clk_enable(inf->clk );
+    
+    inf->dclk = clk_get(&pdev->dev, "lcdc");
+       if (!inf->dclk || IS_ERR(inf->dclk)) 
+    {
+               printk(KERN_ERR "failed to get lcd dclock source\n");
+               ret = -ENOENT;
+               goto unregister_win1fb;
+       }
+    inf->dclk_parent = clk_get(&pdev->dev, "codec_pll");
+    if (!inf->dclk_parent || IS_ERR(inf->dclk_parent))
+    {
+               printk(KERN_ERR "failed to get lcd dclock parent source\n");
+               ret = -ENOENT;
+               goto unregister_win1fb;
+       }
+    inf->dclk_divider= clk_get(&pdev->dev, "lcdc_divider");
+    if (!inf->dclk_divider || IS_ERR(inf->dclk_divider))
+    {
+               printk(KERN_ERR "failed to get lcd clock lcdc_divider source \n");
+               ret = -ENOENT;
+               goto unregister_win1fb;
+       }
+   
+       printk("got and enabled clock\n");  
+    
+       mach_info = pdev->dev.platform_data;
+       if(mach_info)
+    {
+        if( OUT_P888==inf->lcd_info.face ||
+            OUT_P888==inf->tv_info[0].face ||
+            OUT_P888==inf->hdmi_info[0].face )     // set lcdc iomux
+        {
+            printk("set iomux\n");  
+            rk2818_mux_api_set(mach_info->iomux->data24, 1);        
+        } 
+        else 
+        {
+            rk2818_mux_api_set(mach_info->iomux->data18, 1);
+        }        
+        rk2818_mux_api_set(mach_info->iomux->den, 1);
+        rk2818_mux_api_set(mach_info->iomux->vsync, 1);
+    }
+    
+       set_lcd_pin(pdev, 1);
+       mdelay(10);
+       g_pdev = pdev;
+       inf->mcu_usetimer = 1;
+       load_screen(inf->win1fb, 1);
+
+    /* Register framebuffer(win1fb & win0fb) */
+    fbprintk(">> Register framebuffer(win1fb & win0fb) \n");
+    ret = register_framebuffer(inf->win1fb);
+    if(ret<0) 
+    {
+        printk(">> win1fb register_framebuffer fail!\n");
+        ret = -EINVAL;
+               goto release_win0fb;
+    }
+
+//    ret = register_framebuffer(inf->win0fb);
+    if(ret<0) 
+    {
+        printk(">> win0fb register_framebuffer fail!\n");
+        ret = -EINVAL;
+               goto unregister_win1fb;
+    }
+
+#ifdef CONFIG_ANDROID_POWER
+    inf->early_suspend.suspend = rk2818fb_early_suspend;
+    inf->early_suspend.resume = rk2818fb_early_resume;
+    inf->early_suspend.level= 0x0;
+    android_register_early_suspend(&inf->early_suspend);
+#endif
+
+    /* get and request irq */
+    fbprintk(">> get and request irq \n");
+    irq = platform_get_irq(pdev, 0);
+    if (irq < 0) {
+        dev_err(&pdev->dev, "no irq for device\n");
+        ret = -ENOENT;
+        goto release_irq;
+    }
+    ret = request_irq(irq, rk2818fb_irq, IRQF_DISABLED, pdev->name, pdev);
+    if (ret) {
+        dev_err(&pdev->dev, "cannot get irq %d - err %d\n", irq, ret);
+        ret = -EBUSY;
+        goto release_irq;
+    }
+    
+    if((mach_info->iomux->mcu_fmk) && (mach_info->gpio->mcu_fmk_pin))
+    {
+        rk2818_mux_api_set(mach_info->iomux->mcu_fmk, mach_info->gpio->mcu_fmk_pin);
+        ret = request_irq(gpio_to_irq(mach_info->gpio->mcu_fmk_pin), rk2818fb_irqfmk, GPIOEdgelFalling, pdev->name, pdev);
+        if (ret) 
+        {
+            dev_err(&pdev->dev, "cannot get fmk irq %d - err %d\n", irq, ret);
+            ret = -EBUSY;
+            goto release_irq;
+        }
+    }
+#if (0==FMK_USE_HARDTIMER)
+    hrtimer_init(&inf->htimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+       inf->htimer.function = rk2818_fb_dohtimer;
+#endif
+
+    return ret;
+
+release_fmkirq:
+    if(mach_info->gpio->mcu_fmk_pin)        
+        free_irq(gpio_to_irq(mach_info->gpio->mcu_fmk_pin), pdev);
+release_irq:
+       if(irq>=0)
+       free_irq(irq, pdev);  
+unregister_win1fb:
+    unregister_framebuffer(inf->win1fb);
+release_win0fb:
+       if(inf->win0fb)
+               framebuffer_release(inf->win0fb);
+       inf->win0fb = NULL;
+release_win1fb:
+       if(inf->win1fb)
+               framebuffer_release(inf->win1fb);
+       inf->win1fb = NULL;
+release_drvdata:
+       if(inf && inf->reg_vir_base)
+       iounmap(inf->reg_vir_base);
+       if(inf && mem)
+       release_mem_region(inf->reg_phy_base, inf->len);
+       if(inf)
+       kfree(inf);
+       platform_set_drvdata(pdev, NULL);
+       return ret;
+}
+
+static int rk2818fb_remove(struct platform_device *pdev)
+{
+    struct rk2818fb_inf *inf = platform_get_drvdata(pdev);
+    struct fb_info *info = NULL;
+       pm_message_t msg;
+    struct rk2818_fb_mach_info *mach_info = NULL;
+    int irq = 0;
+    
+       fbprintk(">>>>>> %s : %s\n", __FILE__, __FUNCTION__);
+
+    if(!inf) {
+        printk("inf==0, rk2818_fb_remove fail! \n");
+        return -EINVAL;
+    }
+    
+    irq = platform_get_irq(pdev, 0);
+    if (irq >0) 
+    {
+    free_irq(irq, pdev);   
+    }
+     
+    mach_info = pdev->dev.platform_data;
+    if(mach_info->gpio->mcu_fmk_pin)
+    {
+        free_irq(gpio_to_irq(mach_info->gpio->mcu_fmk_pin), pdev);
+    }
+
+#ifdef CONFIG_ANDROID_POWER
+    android_unregister_early_suspend(&inf->early_suspend);
+#endif
+
+       set_lcd_pin(pdev, 0);
+
+    // blank the lcdc
+    if(inf->win0fb)
+        win0fb_blank(FB_BLANK_POWERDOWN, inf->win0fb);
+    if(inf->win1fb)
+        win1fb_blank(FB_BLANK_POWERDOWN, inf->win1fb);
+    
+       // suspend the lcdc
+       rk2818fb_suspend(pdev, msg);
+
+    // unmap memory and release framebuffer
+    if(inf->win0fb) {
+        info = inf->win0fb;
+        if (info->screen_base) {
+               dma_free_writecombine(NULL, PAGE_ALIGN(info->fix.smem_len),info->screen_base, info->fix.smem_start);
+               info->screen_base = 0;
+               info->fix.smem_start = 0;
+               info->fix.smem_len = 0;
+        }
+        unregister_framebuffer(inf->win0fb);
+        framebuffer_release(inf->win0fb);
+        inf->win0fb = NULL;
+    }
+    if(inf->win1fb) {
+        info = inf->win1fb;
+        if (info->screen_base) {
+               dma_free_writecombine(NULL, PAGE_ALIGN(info->fix.smem_len),info->screen_base, info->fix.smem_start);
+               info->screen_base = 0;
+               info->fix.smem_start = 0;
+               info->fix.smem_len = 0;
+        }
+        unregister_framebuffer(inf->win1fb);
+        framebuffer_release(inf->win1fb);
+        inf->win1fb = NULL;
+    }
+
+       if (inf->clk)
+    {
+               clk_disable(inf->clk);
+               clk_put(inf->clk);
+               inf->clk = NULL;
+       }
+    if (inf->dclk)
+    {
+               clk_disable(inf->dclk);
+               clk_put(inf->dclk);
+               inf->dclk = NULL;
+       }
+    
+    kfree(inf);
+    platform_set_drvdata(pdev, NULL);
+
+    return 0;
+}
+
+static int rk2818fb_suspend(struct platform_device *pdev, pm_message_t msg)
+{
+    struct rk2818fb_inf *inf = platform_get_drvdata(pdev);
+       
+    fbprintk(">>>>>> %s : %s\n", __FILE__, __FUNCTION__);
+
+    if(!inf) {
+        printk("inf==0, rk2818fb_suspend fail! \n");
+        return -EINVAL;
+    }
+
+       if(inf->cur_screen->standby)
+       {
+               fbprintk(">>>>>> power down the screen! \n");
+               inf->cur_screen->standby(1);
+       }
+
+    LcdMskReg(inf, DSP_CTRL1, m_BLANK_MODE , v_BLANK_MODE(1));    
+    LcdMskReg(inf, SYS_CONFIG, m_STANDBY, v_STANDBY(1));
+       LcdWrReg(inf, REG_CFG_DONE, 0x01);
+
+       if(!inf->in_suspend)
+       {
+               fbprintk(">>>>>> diable the lcdc clk! \n");
+               msleep(100);
+       if (inf->dclk)
+        {
+            clk_disable(inf->dclk);
+        }
+               inf->in_suspend = 1;
+       }
+
+       set_lcd_pin(pdev, 0);
+
+       return 0;
+}
+
+
+static int rk2818fb_resume(struct platform_device *pdev)
+{
+    struct rk2818fb_inf *inf = platform_get_drvdata(pdev);
+    struct rk28fb_screen *screen = inf->cur_screen;
+
+    fbprintk(">>>>>> %s : %s\n", __FILE__, __FUNCTION__);
+
+    if(!inf) {
+        printk("inf==0, rk2818fb_resume fail! \n");
+        return -EINVAL;
+    }
+
+       set_lcd_pin(pdev, 1);
+
+       if(inf->in_suspend)
+       {
+           inf->in_suspend = 0;
+       fbprintk(">>>>>> eable the lcdc clk! \n");
+        if (inf->dclk)
+        {
+            clk_enable(inf->dclk);
+            clk_set_rate(inf->dclk, screen->pixclock);
+        }        
+        msleep(100);
+       }
+
+    LcdMskReg(inf, DSP_CTRL1, m_BLANK_MODE , v_BLANK_MODE(0));    
+    LcdMskReg(inf, SYS_CONFIG, m_STANDBY, v_STANDBY(0));
+    LcdWrReg(inf, REG_CFG_DONE, 0x01);
+
+       if(inf->cur_screen->standby)
+       {
+               fbprintk(">>>>>> power on the screen! \n");
+               inf->cur_screen->standby(0);
+       }
+    msleep(100);
+
+       return 0;
+}
+
+
+#ifdef CONFIG_ANDROID_POWER
+static void rk2818fb_early_suspend(android_early_suspend_t *h)
+{ 
+       pm_message_t msg;
+
+    fbprintk(">>>>>> %s : %s\n", __FILE__, __FUNCTION__);
+
+    if(g_pdev) 
+    {
+               rk2818fb_suspend(g_pdev, msg);
+    }
+    else 
+    {
+        printk("g_pdev==0, rk2818fb_early_suspend fail! \n");
+        return;
+       }
+}
+static void rk2818fb_early_resume(android_early_suspend_t *h)
+{
+    fbprintk(">>>>>> %s : %s\n", __FILE__, __FUNCTION__);
+
+    if(g_pdev)
+    { 
+               rk2818fb_resume(g_pdev);
+       } 
+    else 
+    {
+        printk("g_pdev==0, rk2818fb_early_resume fail! \n");
+        return;
+    }
+}
+#endif
+static void rk2818fb_shutdown(struct platform_device *pdev)
+{
+    struct rk2818fb_inf *inf = platform_get_drvdata(pdev);
+    mdelay(300);
+       //printk("----------------------------rk2818fb_shutdown----------------------------\n");
+       set_lcd_pin(pdev, 0);   
+    if (inf->dclk)
+    {
+        clk_disable(inf->dclk);
+    }
+    if (inf->clk)
+    {
+        clk_disable(inf->clk);
+    }          
+}
+
+static struct platform_driver rk2818fb_driver = {
+       .probe          = rk2818fb_probe,
+       .remove         = rk2818fb_remove,
+       .driver         = {
+               .name   = "rk2818-fb",
+               .owner  = THIS_MODULE,
+       },
+       .shutdown   = rk2818fb_shutdown,
+};
+
+static int __init rk2818fb_init(void)
+{
+    fbprintk(">>>>>> %s : %s\n", __FILE__, __FUNCTION__);
+    return platform_driver_register(&rk2818fb_driver);
+}
+
+static void __exit rk2818fb_exit(void)
+{
+    fbprintk(">>>>>> %s : %s\n", __FILE__, __FUNCTION__);
+    platform_driver_unregister(&rk2818fb_driver);
+}
+
+//subsys_initcall(rk2818fb_init);
+
+module_init(rk2818fb_init);
+module_exit(rk2818fb_exit);
+
+
+MODULE_AUTHOR("  zyw@rock-chips.com");
+MODULE_DESCRIPTION("Driver for rk2818 fb device");
+MODULE_LICENSE("GPL");
+
+
diff --git a/drivers/video/rk2818_fb.h b/drivers/video/rk2818_fb.h
new file mode 100644 (file)
index 0000000..62d8556
--- /dev/null
@@ -0,0 +1,413 @@
+/* drivers/video/rk2818_fb.h
+ *
+ * Copyright (C) 2010 ROCKCHIP, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __ARCH_ARM_MACH_RK2818_FB_H
+#define __ARCH_ARM_MACH_RK2818_FB_H
+
+/********************************************************************
+**                            ºê¶¨Òå                                *
+********************************************************************/
+/* ÊäÍùÆÁµÄÊý¾Ý¸ñʽ */
+#define OUT_P888            0
+#define OUT_P666            1
+#define OUT_P565            2
+#define OUT_S888x           4
+#define OUT_CCIR656         6
+#define OUT_S888            8
+#define OUT_S888DUMY        12
+#define OUT_P16BPP4         24  //Ä£Äⷽʽ,¿ØÖÆÆ÷²¢²»Ö§³Ö
+
+/* Low Bits Mask */
+#define m_WORDLO            (0xffff<<0)
+#define m_WORDHI            (0xffff<<16)
+#define v_WORDLO(x)         (((x)&0xffff)<<0)
+#define v_WORDHI(x)         (((x)&0xffff)<<16)
+
+#define m_BIT11LO           (0x7ff<<0)
+#define m_BIT11HI           (0x7ff<<16)
+#define v_BIT11LO(x)        (((x)&0x7ff)<<0)
+#define v_BIT11HI(x)        (((x)&0x7ff)<<16)
+
+
+/* SYS_CONFIG */
+#define m_W1_FORMAT          (1<<0)
+#define m_W0_FORMAT          (7<<1)
+#define m_W1_ROLLER          (1<<4)
+#define m_W0_ROLLER          (1<<5)
+#define m_INTERIACE_EN       (1<<6)      
+#define m_MPEG2_I2P_EN       (1<<7)
+#define m_W0_ROTATE          (1<<8)
+#define m_W1_ENABLE          (1<<9)
+#define m_W0_ENABLE          (1<<10)
+#define m_HWC_ENABLE         (1<<11)
+#define m_HWC_RELOAD_EN         (1<<12)
+#define m_W1_INTERLACE_READ    (1<<13)
+#define m_W0_INTERLACE_READ    (1<<14)
+#define m_STANDBY            (1<<15)
+#define m_W1_HWC_INCR        (31<<16)
+#define m_W1_HWC_BURST       (7<<21)
+#define m_W0_INCR            (31<<24)
+#define m_W0_BURST           (7<<29)
+#define v_W1_FORMAT(x)          (((x)&1)<<0)
+#define v_W0_FORMAT(x)          (((x)&7)<<1)
+#define v_W1_ROLLER(x)          (((x)&1)<<4)
+#define v_W0_ROLLER(x)          (((x)&1)<<5)
+#define v_INTERIACE_EN(x)          (((x)&1)<<6)      
+#define v_MPEG2_I2P_EN(x)          (((x)&1)<<7)
+#define v_W0_ROTATE(x)          (((x)&1)<<8)
+#define v_W1_ENABLE(x)          (((x)&1)<<9)
+#define v_W0_ENABLE(x)          (((x)&1)<<10)
+#define v_HWC_ENABLE(x)         (((x)&1)<<11)
+#define v_HWC_RELOAD_EN(x)         (((x)&1)<<12)
+#define v_W1_INTERLACE_READ(x)    (((x)&1)<<13)
+#define v_W0_INTERLACE_READ(x)    (((x)&1)<<14)
+#define v_STANDBY(x)            (((x)&1)<<15)
+#define v_W1_HWC_INCR(x)        (((x)&31)<<16)
+#define v_W1_HWC_BURST(x)       (((x)&7)<<21)
+#define v_W0_INCR(x)            (((x)&31)<<24)
+#define v_W0_BURST(x)           (((x)&7)<<29)
+
+//LCDC_SWAP_CTRL
+#define m_W1_565_RB_SWAP        (1<<0)
+#define m_W0_565_RB_SWAP        (1<<1)
+#define m_W0_YRGB_M8_SWAP       (1<<2)
+#define m_W0_YRGB_R_SHIFT_SWAP  (1<<3)
+#define m_W0_CBR_R_SHIFT_SWAP   (1<<4)
+#define m_W0_YRGB_16_SWAP       (1<<5)
+#define m_W0_YRGB_8_SWAP        (1<<6)
+#define m_W0_CBR_16_SWAP        (1<<7)
+#define m_W0_CBR_8_SWAP         (1<<8)
+#define m_W1_16_SWAP            (1<<9)
+#define m_W1_8_SWAP             (1<<10)
+#define m_W1_R_SHIFT_SWAP       (1<<11)
+#define m_OUTPUT_BG_SWAP        (1<<12)
+#define m_OUTPUT_RB_SWAP        (1<<13)
+#define m_OUTPUT_RG_SWAP        (1<<14)
+#define m_DELTA_SWAP            (1<<15)
+#define m_DUMMY_SWAP            (1<<16)
+#define m_W0_YRGB_HL8_SWAP      (1<<17)
+#define v_W1_565_RB_SWAP(x)        (((x)&1)<<0)
+#define v_W0_565_RB_SWAP(x)        (((x)&1)<<1)
+#define v_W0_YRGB_M8_SWAP(x)       (((x)&1)<<2)
+#define v_W0_YRGB_R_SHIFT_SWAP(x)  (((x)&1)<<3)
+#define v_W0_CBR_R_SHIFT_SWAP(x)   (((x)&1)<<4)
+#define v_W0_YRGB_16_SWAP(x)       (((x)&1)<<5)
+#define v_W0_YRGB_8_SWAP(x)        (((x)&1)<<6)
+#define v_W0_CBR_16_SWAP(x)        (((x)&1)<<7)
+#define v_W0_CBR_8_SWAP(x)         (((x)&1)<<8)
+#define v_W1_16_SWAP(x)            (((x)&1)<<9)
+#define v_W1_8_SWAP(x)             (((x)&1)<<10)
+#define v_W1_R_SHIFT_SWAP(x)       (((x)&1)<<11)
+#define v_OUTPUT_BG_SWAP(x)        (((x)&1)<<12)
+#define v_OUTPUT_RB_SWAP(x)        (((x)&1)<<13)
+#define v_OUTPUT_RG_SWAP(x)        (((x)&1)<<14)
+#define v_DELTA_SWAP(x)            (((x)&1)<<15)
+#define v_DUMMY_SWAP(x)            (((x)&1)<<16)
+#define v_W0_YRGB_HL8_SWAP(x)      (((x)&1)<<17)
+
+//LCDC_MCU_TIMING_CTRL
+#define m_MCU_WRITE_PERIOD      (31<<0)
+#define m_MCU_CS_ST             (31<<5)
+#define m_MCU_CS_END            (31<<10)
+#define m_MCU_RW_ST             (31<<15)
+#define m_MCU_RW_END            (31<<20)
+#define m_MCU_HOLD_STATUS          (1<<26)
+#define m_MCU_HOLDMODE_SELECT     (1<<27)
+#define m_MCU_HOLDMODE_FRAME_ST   (1<<28)
+#define m_MCU_RS_SELECT            (1<<29)
+#define m_MCU_BYPASSMODE_SELECT   (1<<30)
+#define m_MCU_OUTPUT_SELECT        (1<<31)
+#define v_MCU_WRITE_PERIOD(x)      (((x)&31)<<0)
+#define v_MCU_CS_ST(x)          (((x)&31)<<5)
+#define v_MCU_CS_END(x)         (((x)&31)<<10)
+#define v_MCU_RW_ST(x)          (((x)&31)<<15)
+#define v_MCU_RW_END(x)         (((x)&31)<<20)
+#define v_MCU_HOLD_STATUS(x)          (((x)&1)<<26)
+#define v_MCU_HOLDMODE_SELECT(x)     (((x)&1)<<27)
+#define v_MCU_HOLDMODE_FRAME_ST(x)   (((x)&1)<<28)
+#define v_MCU_RS_SELECT(x)            (((x)&1)<<29)
+#define v_MCU_BYPASSMODE_SELECT(x)   (((x)&1)<<30)
+#define v_MCU_OUTPUT_SELECT(x)        (((x)&1)<<31)
+
+//LCDC_ BLEND_CTRL
+#define m_W1_BLEND_EN          (1<<0) 
+#define m_W0_BLEND_EN          (1<<1)
+#define m_HWC_BLEND_EN          (1<<2)
+#define m_W1_BLEND_FACTOR_SELECT     (1<<3)
+#define m_W0_BLEND_FACTOR_SELECT     (1<<4)
+#define m_W0W1_OVERLAY                 (1<<5)
+#define m_HWC_BLEND_FACTOR    (15<<12)
+#define m_W1_BLEND_FACTOR     (0xff<<16)
+#define m_W0_BLEND_FACTOR     (0xff<<24)
+#define v_W1_BLEND_EN(x)          (((x)&1)<<0) 
+#define v_W0_BLEND_EN(x)          (((x)&1)<<1)
+#define v_HWC_BLEND_EN(x)          (((x)&1)<<2)
+#define v_W1_BLEND_FACTOR_SELECT(x)     (((x)&1)<<3)
+#define v_W0_BLEND_FACTOR_SELECT(x)     (((x)&1)<<4)
+#define v_W0W1_OVERLAY(x)                 (((x)&1)<<5)
+#define v_HWC_BLEND_FACTOR(x)    (((x)&15)<<12)
+#define v_W1_BLEND_FACTOR(x)     (((x)&0xff)<<16)
+#define v_W0_BLEND_FACTOR(x)     (((x)&0xff)<<24)
+
+//LCDC_WIN0_COLOR_KEY_CTRL / LCDC_WIN1_COLOR_KEY_CTRL
+#define m_KEYCOLOR          (0xffffff<<0)
+#define m_KEYCOLOR_B          (0xff<<0)    
+#define m_KEYCOLOR_G          (0xff<<8)
+#define m_KEYCOLOR_R          (0xff<<16)
+#define m_COLORKEY_EN         (1<<24) 
+#define v_KEYCOLOR(x)          (((x)&0xffffff)<<0)
+#define v_KEYCOLOR_B(x)          (((x)&0xff)<<0)    
+#define v_KEYCOLOR_G(x)         (((x)&0xff)<<8)
+#define v_KEYCOLOR_R(x)          (((x)&0xff)<<16)
+#define v_COLORKEY_EN(x)         (((x)&1)<<24)
+
+//LCDC_DEFLICKER_SCL_OFFSET
+#define m_W0_YRGB_VSD_OFFSET      (0xff<<0)
+#define m_W0_YRGB_VSP_OFFSET      (0xff<<8)
+#define m_W1_VSD_OFFSET           (0xff<<16)
+#define m_W1_VSP_OFFSET           (0xff<<24)
+#define v_W0_YRGB_VSD_OFFSET(x)      (((x)&0xff)<<0)
+#define v_W0_YRGB_VSP_OFFSET(x)      (((x)&0xff)<<8)
+#define v_W1_VSD_OFFSET(x)           (((x)&0xff)<<16)
+#define v_W1_VSP_OFFSET(x)           (((x)&0xff)<<24)
+
+//LCDC_DSP_CTRL_REG0
+#define m_DISPLAY_FORMAT             (0xf<<0)
+#define m_HSYNC_POLARITY             (1<<4)
+#define m_VSYNC_POLARITY             (1<<5)
+#define m_DEN_POLARITY               (1<<6)
+#define m_DCLK_POLARITY              (1<<7)
+#define m_COLOR_SPACE_CONVERSION     (3<<8)
+#define m_I2P_THRESHOLD_Y            (0x3f<<10)        
+#define m_I2P_THRESHOLD_CBR          (0x3f<<16) 
+#define m_565_TO_888_REPLICATION_EN  (1<<22)
+#define m_DITHERING_MODE             (1<<23)
+#define m_DITHERING_EN               (1<<24)
+#define m_DROP_LINE_W1               (1<<25)
+#define m_DROP_LINE_W0               (1<<26)
+#define m_I2P_CUR_POLARITY           (1<<27)
+#define m_INTERLACE_FIELD_POLARITY   (1<<28)
+#define m_YUV_CLIP_MODE              (1<<29)
+#define m_I2P_FILTER_EN              (1<<30) 
+#define m_I2P_FILTER_PARAM           (1<<31)  
+#define v_DISPLAY_FORMAT(x)            (((x)&0xf)<<0)
+#define v_HSYNC_POLARITY(x)             (((x)&1)<<4)
+#define v_VSYNC_POLARITY(x)             (((x)&1)<<5)
+#define v_DEN_POLARITY(x)               (((x)&1)<<6)
+#define v_DCLK_POLARITY(x)              (((x)&1)<<7)
+#define v_COLOR_SPACE_CONVERSION(x)     (((x)&3)<<8)
+#define v_I2P_THRESHOLD_Y(x)            (((x)&0x3f)<<10)        
+#define v_I2P_THRESHOLD_CBR(x)          (((x)&0x3f)<<16) 
+#define v_565_TO_888_REPLICATION_EN(x)  (((x)&1)<<22)
+#define v_DITHERING_MODE(x)             (((x)&1)<<23)
+#define v_DITHERING_EN(x)               (((x)&1)<<24)
+#define v_DROP_LINE_W1(x)               (((x)&1)<<25)
+#define v_DROP_LINE_W0(x)               (((x)&1)<<26)
+#define v_I2P_CUR_POLARITY(x)           (((x)&1)<<27)
+#define v_INTERLACE_FIELD_POLARITY(x)   (((x)&1)<<28)
+#define v_YUV_CLIP_MODE(x)              (((x)&1)<<29)
+#define v_I2P_FILTER_EN(x)              (((x)&1)<<30) 
+#define v_I2P_FILTER_PARAM(x)           (((x)&1)<<31)  
+
+//LCDC_DSP_CTRL_REG1
+#define m_BG_COLOR                    (0xffffff<<0)
+#define m_BG_B                        (0xff<<0)          
+#define m_BG_G                        (0xff<<8)   
+#define m_BG_R                        (0xff<<16)   
+#define m_BLANK_MODE                  (1<<24) 
+#define m_BLACK_MODE                  (1<<25) 
+#define m_W1_SD_DEFLICKER_EN            (1<<26)
+#define m_W1_SP_DEFLICKER_EN            (1<<27)
+#define m_W0CR_SD_DEFLICKER_EN          (1<<28)
+#define m_W0CR_SP_DEFLICKER_EN          (1<<29)
+#define m_W0YRGB_SD_DEFLICKER_EN        (1<<30)
+#define m_W0YRGB_SP_DEFLICKER_EN        (1<<31)
+#define v_BG_COLOR(x)                    (((x)&0xffffff)<<0)  
+#define v_BG_B(x)                        (((x)&0xff)<<0)          
+#define v_BG_G(x)                        (((x)&0xff)<<8)   
+#define v_BG_R(x)                        (((x)&0xff)<<16)   
+#define v_BLANK_MODE(x)                  (((x)&1)<<24) 
+#define v_BLACK_MODE(x)                  (((x)&1)<<25) 
+#define v_W1_SD_DEFLICKER_EN(x)            (((x)&1)<<26)
+#define v_W1_SP_DEFLICKER_EN(x)            (((x)&1)<<27)
+#define v_W0CR_SD_DEFLICKER_EN(x)          (((x)&1)<<28)
+#define v_W0CR_SP_DEFLICKER_EN(x)          (((x)&1)<<29)
+#define v_W0YRGB_SD_DEFLICKER_EN(x)        (((x)&1)<<30)
+#define v_W0YRGB_SP_DEFLICKER_EN(x)        (((x)&1)<<31)
+
+//LCDC_INT_STATUS
+#define m_HOR_START         (1<<0)
+#define m_FRM_START         (1<<1)
+#define m_SCANNING_FLAG     (1<<2)
+#define m_HOR_STARTMASK     (1<<3)
+#define m_FRM_STARTMASK     (1<<4)
+#define m_SCANNING_MASK     (1<<5)
+#define m_HOR_STARTCLEAR    (1<<6)
+#define m_FRM_STARTCLEAR    (1<<7)
+#define m_SCANNING_CLEAR    (1<<8)
+#define m_SCAN_LINE_NUM     (0x7ff<<9)
+#define v_HOR_START(x)         (((x)&1)<<0)
+#define v_FRM_START(x)         (((x)&1)<<1)
+#define v_SCANNING_FLAG(x)     (((x)&1)<<2)
+#define v_HOR_STARTMASK(x)     (((x)&1)<<3)
+#define v_FRM_STARTMASK(x)     (((x)&1)<<4)
+#define v_SCANNING_MASK(x)     (((x)&1)<<5)
+#define v_HOR_STARTCLEAR(x)    (((x)&1)<<6)
+#define v_FRM_STARTCLEAR(x)    (((x)&1)<<7)
+#define v_SCANNING_CLEAR(x)    (((x)&1)<<8)
+#define v_SCAN_LINE_NUM(x)     (((x)&0x7ff)<<9)
+
+#define m_VIRWIDTH       (0xffff<<0)
+#define m_VIRHEIGHT      (0xffff<<16)
+#define v_VIRWIDTH(x)       (((x)&0xffff)<<0)
+#define v_VIRHEIGHT(x)      (((x)&0xffff)<<16)
+
+#define m_ACTWIDTH       (0xffff<<0)
+#define m_ACTHEIGHT      (0xffff<<16)
+#define v_ACTWIDTH(x)       (((x)&0xffff)<<0)
+#define v_ACTHEIGHT(x)      (((x)&0xffff)<<16)
+
+#define m_VIRST_X      (0xffff<<0)
+#define m_VIRST_Y      (0xffff<<16)
+#define v_VIRST_X(x)      (((x)&0xffff)<<0)
+#define v_VIRST_Y(x)      (((x)&0xffff)<<16)
+
+#define m_PANELST_X      (0x3ff<<0)
+#define m_PANELST_Y      (0x3ff<<16)
+#define v_PANELST_X(x)      (((x)&0x3ff)<<0)
+#define v_PANELST_Y(x)      (((x)&0x3ff)<<16)
+
+#define m_PANELWIDTH       (0x3ff<<0)
+#define m_PANELHEIGHT      (0x3ff<<16)
+#define v_PANELWIDTH(x)       (((x)&0x3ff)<<0)
+#define v_PANELHEIGHT(x)      (((x)&0x3ff)<<16)
+
+#define m_HWC_B                 (0xff<<0)
+#define m_HWC_G                 (0xff<<8)
+#define m_HWC_R                 (0xff<<16)
+#define m_W0_YRGB_HSP_OFFSET    (0xff<<24)
+#define m_W0_YRGB_HSD_OFFSET    (0xff<<24)
+#define v_HWC_B(x)                 (((x)&0xff)<<0)
+#define v_HWC_G(x)                 (((x)&0xff)<<8)
+#define v_HWC_R(x)                 (((x)&0xff)<<16)
+#define v_W0_YRGB_HSP_OFFSET(x)    (((x)&0xff)<<24)
+#define v_W0_YRGB_HSD_OFFSET(x)    (((x)&0xff)<<24)
+
+
+//Panel display scanning
+#define m_PANEL_HSYNC_WIDTH             (0x3ff<<0)
+#define m_PANEL_HORIZONTAL_PERIOD       (0x3ff<<16)
+#define v_PANEL_HSYNC_WIDTH(x)             (((x)&0x3ff)<<0)
+#define v_PANEL_HORIZONTAL_PERIOD(x)       (((x)&0x3ff)<<16)
+
+#define m_PANEL_END              (0x3ff<<0)  
+#define m_PANEL_START            (0x3ff<<16)
+#define v_PANEL_END(x)              (((x)&0x3ff)<<0)  
+#define v_PANEL_START(x)            (((x)&0x3ff)<<16)
+
+#define m_PANEL_VSYNC_WIDTH             (0x3ff<<0)
+#define m_PANEL_VERTICAL_PERIOD       (0x3ff<<16)
+#define v_PANEL_VSYNC_WIDTH(x)             (((x)&0x3ff)<<0)
+#define v_PANEL_VERTICAL_PERIOD(x)       (((x)&0x3ff)<<16)
+//-----------
+
+#define m_HSCALE_FACTOR        (0xffff<<0)  
+#define m_VSCALE_FACTOR        (0xffff<<16)
+#define v_HSCALE_FACTOR(x)        (((x)&0xffff)<<0)  
+#define v_VSCALE_FACTOR(x)        (((x)&0xffff)<<16)
+
+#define m_W0_CBR_HSD_OFFSET   (0xff<<0)
+#define m_W0_CBR_HSP_OFFSET   (0xff<<8)
+#define m_W0_CBR_VSD_OFFSET   (0xff<<16)
+#define m_W0_CBR_VSP_OFFSET   (0xff<<24)
+#define v_W0_CBR_HSD_OFFSET(x)   (((x)&0xff)<<0)
+#define v_W0_CBR_HSP_OFFSET(x)   (((x)&0xff)<<8)
+#define v_W0_CBR_VSD_OFFSET(x)   (((x)&0xff)<<16)
+#define v_W0_CBR_VSP_OFFSET(x)   (((x)&0xff)<<24)
+
+
+#define FB0_IOCTL_STOP_TIMER_FLUSH             0x6001
+#define FB0_IOCTL_SET_PANEL                            0x6002
+
+#define FB1_IOCTL_GET_PANEL_SIZE               0x5001
+#define FB1_IOCTL_SET_YUV_ADDR                 0x5002
+#define FB1_TOCTL_SET_MCU_DIR                  0x5003
+
+
+/********************************************************************
+**                          ½á¹¹¶¨Òå                                *
+********************************************************************/
+/* LCDCµÄ¼Ä´æÆ÷½á¹¹ */
+typedef volatile struct tagLCDC_REG
+{
+    /* offset 0x00~0xc0 */
+    unsigned int SYS_CONFIG;              //SYSTEM configure register
+    unsigned int SWAP_CTRL;               //Data SWAP control
+    unsigned int MCU_TIMING_CTRL;         //MCU TIMING control register
+    unsigned int BLEND_CTRL;              //Blending control register
+    unsigned int WIN0_COLOR_KEY_CTRL;     //Win0 blending control register
+    unsigned int WIN1_COLOR_KEY_CTRL;     //Win1 blending control register
+    unsigned int DEFLICKER_SCL_OFFSET;    //Deflick scaling start point offset
+    unsigned int DSP_CTRL0;               //Display control register0
+    unsigned int DSP_CTRL1;               //Display control register1
+    unsigned int INT_STATUS;              //Interrupt status register
+    unsigned int WIN0_VIR;                //WIN0 virtual display width/height
+    unsigned int WIN0_YRGB_MST;           //Win0 active YRGB memory start address
+    unsigned int WIN0_CBR_MST;            //Win0 active Cbr memory start address
+    unsigned int WIN0_ACT_INFO;           //Win0 active window width/height
+    unsigned int WIN0_ROLLER_INFO;        //Win0 x and y value of start point in roller mode
+    unsigned int WIN0_DSP_ST;             //Win0 display start point on panel
+    unsigned int WIN0_DSP_INFO;           //Win0 display width/height on panel
+    unsigned int WIN1_VIR;                //Win1 virtual display width/height
+    unsigned int WIN1_YRGB_MST;            //Win1 active  memory start address
+    unsigned int WIN1_ACT_INFO;           //Win1 active width /height
+    unsigned int WIN1_ROLLER_INFO;        //Win1 x and y value of start point in roller mode
+    unsigned int WIN1_DSP_ST;             //Win1 display start point on panel
+    unsigned int WIN1_DSP_INFO;           //Win1 display width/height on panel
+    unsigned int HWC_MST;                 //HWC memory start address
+    unsigned int HWC_DSP_ST;              //HWC display start point on panel
+    unsigned int HWC_COLOR_LUT0;          //Hardware cursor color 2¡¯b01 look up table 0
+    unsigned int HWC_COLOR_LUT1;          //Hardware cursor color 2¡¯b10 look up table 1
+    unsigned int HWC_COLOR_LUT2;          //Hardware cursor color 2¡¯b11 look up table 2
+    unsigned int DSP_HTOTAL_HS_END;       //Panel scanning horizontal width and hsync pulse end point
+    unsigned int DSP_HACT_ST_END;         //Panel active horizontal scanning start/end point
+    unsigned int DSP_VTOTAL_VS_END;       //Panel scanning vertical height and vsync pulse end point
+    unsigned int DSP_VACT_ST_END;         //Panel active vertical scanning start/end point
+    unsigned int DSP_VS_ST_END_F1;        //Vertical scanning start point and vsync pulse end point of even filed in interlace mode
+    unsigned int DSP_VACT_ST_END_F1;      //Vertical scanning active start/end point of even filed in interlace mode
+    unsigned int WIN0_SD_FACTOR_Y;        //Win0 YRGB scaling down factor setting
+    unsigned int WIN0_SP_FACTOR_Y;        //Win0 YRGB scaling up factor setting
+    unsigned int WIN0_CBR_SCL_OFFSET;     //Win0 Cbr scaling start point offset
+    unsigned int WIN1_SCL_FACTOR;         //Win1 scaling factor setting
+    unsigned int I2P_REF0_MST_Y;          //I2P field 0 memory start address
+    unsigned int I2P_REF0_MST_CBR;        //I2P field 0 memory start address
+    unsigned int I2P_REF1_MST_Y;          //I2P field 2 memory start address
+    unsigned int I2P_REF1_MST_CBR;        //I2P field 2 memory start address
+    unsigned int WIN0_YRGB_VIR_MST;       //Win0 virtual memory start address
+    unsigned int WIN0_CBR_VIR_MST;        //Win0 virtual memory start address
+    unsigned int WIN1_VIR_MST;            //Win1 virtual memory start address
+    unsigned int WIN0_SD_FACTOR_CBR;      //Win0 CBR scaling down factor setting
+    unsigned int WIN0_SP_FACTOR_CBR;      //Win0 CBR scaling up factor setting
+    unsigned int reserved0;
+    unsigned int REG_CFG_DONE;            //REGISTER CONFIG FINISH
+    unsigned int reserved1[(0x500-0xc4)/4];
+    unsigned int MCU_BYPASS_WPORT;         //MCU BYPASS MODE, DATA Write Port
+} LCDC_REG, *pLCDC_REG;
+
+
+extern void __init rk2818_add_device_lcdc(void);
+extern int mcu_ioctl(unsigned int cmd, unsigned long arg);
+
+#endif