Roverbook steel. Проект Debian вместо Android.

Назад Главная


Roverbook steel. Проект Debian вместо Android.

Roverbook steel FD
drivers\video\rk2818_fb.c
/*
 * 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 <asm/arch/iomux.h>
#include <asm/arch/gpio.h>
#include <asm/arch/hardware.h>

#include <asm/arch/rk28_scu.h>

//#include <asm/uaccess.h>

#ifdef CONFIG_ANDROID_POWER
#include <linux/android_power.h>
#endif
#ifdef CONFIG_ANX7150
#include <asm/arch/anx7150.h>
#endif
#ifdef CONFIG_TV_RK1000
#include <asm/arch/rk1000_tv.h>
#endif

#include "./display/screen/screen.h"

#define FB_TEST                 1       

#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

#define CURSOR_BUF_SIZE         256      //RK2818 cursor need 256B buf
#if 0
	 #define fbprintk(msg...)	printk(msg);
#else
	#define fbprintk(msg...)
#endif

#if 0
	#define fbprintk2(msg...)	printk(msg);
#else
	#define fbprintk2(msg...)
#endif

#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
    struct clk      *clk_share_mem;   //lcdc share memory 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;

    char __iomem *cursor_base;   /* cursor Virtual address*/
    __u32 cursor_size;           /* Amount of ioremapped VRAM or 0 */ 
    unsigned long  cursor_start;

    struct rk28fb_screen lcd_info;
    struct rk28fb_screen tv_info[5];
    struct rk28fb_screen hdmi_info[3];
    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;

//zyw test for a7
u32 gwin1bufv = 0;
u32 gwin1bufp = 0;
u8 testflag=0;

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;
int* pmem_pos;
int* pmem_scale_pos;
int* pmem_st;
int send_frame=0;
struct delayed_work frame_delay_work;	
#define SCALE_INFO_OFFSET	0x3200

void frame_do_work(struct work_struct *work) {
    if(send_frame != 0) {
        struct rk2818fb_inf *inf = platform_get_drvdata(g_pdev);
        struct fb_var_screeninfo *var0;//= inf->win0fb->var;
        struct win0_par *par;// = inf->win0fb->par;
        struct fb_fix_screeninfo *fix0;// = inf->win0fb->fix;
        struct rk28fb_screen *screen;
        
        screen = inf->cur_screen;
        par = inf->win0fb->par;
        var0 = &(inf->win0fb->var);
        fix0 = &(inf->win0fb->fix);

        u32 pos_inf;
        u32 data[2];
        u32 y_offset=0, y_addr=0;
        
      	u32 scale_data[6];
        u32 ScaleX,ScaleY;
        u32 dsp_posx,dsp_posy;
        u32 actwidth,actheight;
        u32 vir_pos;
        u32 i, j;
        //printk("FRAMEINT:pmem_start= %d; status_value= %d pos= %p\n \n",*pmem_st,*(pmem_st+1),*(pmem_pos));
        if(*pmem_st == 0) {
                pmem_pos = (int *)(pmem_st+2);
                *(pmem_st+1)= 0;
        } else if(*(pmem_st+1) < *pmem_st) {
            data[0] = ((*pmem_pos >> 16) & 0xffff)&(~0x1);
            data[1] = *pmem_pos & 0x0000ffff;
            //data[0] = data[0] & (~0x1);
            y_offset = par->y_offset+(data[1]*var0->xres_virtual + data[0])*2+LcdRdReg(inf, WIN0_YRGB_VIR_MST);

            LcdWrReg(inf, WIN0_YRGB_MST, y_offset);
            LcdWrReg(inf, REG_CFG_DONE, 0x01);
            pmem_pos += 1;
            (*(pmem_st+1))++;
        }
        //printk("Scale addr: srcstatus: %d,deststatus %d\n",*(pmem_st+SCALE_INFO_OFFSET),*(pmem_st+1+SCALE_INFO_OFFSET));
		if(*(pmem_st+SCALE_INFO_OFFSET) == 0) {
	        pmem_scale_pos = (int *)(pmem_st+2+SCALE_INFO_OFFSET);
	        *(pmem_st+SCALE_INFO_OFFSET+1) = 0;
		} else if(*(pmem_st+SCALE_INFO_OFFSET+1) < *(pmem_st+SCALE_INFO_OFFSET)) {
			for( i=0, j=0; i<5; i+=2, j++) {
				scale_data[i] = (*(pmem_scale_pos+j) & 0xffff0000) >>16;
				scale_data[i+1] = *(pmem_scale_pos+j) & 0x0000ffff;
			}
            //printk("Factory: %d, %d, %d, %d, %d, %d",scale_data[0],scale_data[1],scale_data[2],scale_data[3],scale_data[4],scale_data[5]);
            ScaleX=scale_data[4];
            ScaleY=scale_data[5];
            dsp_posx = scale_data[2] + (screen->left_margin + screen->hsync_len);
            dsp_posy = scale_data[3] + (screen->upper_margin + screen->vsync_len);
            
            vir_pos = par->y_offset+(scale_data[0]+scale_data[1]*var0->xres_virtual)*2+LcdRdReg(inf,WIN0_YRGB_VIR_MST);
            
            LcdMskReg(inf, WIN0_DSP_ST, m_BIT11LO | m_BIT11HI, v_BIT11LO(dsp_posx) | v_BIT11HI(dsp_posy));
            
            actwidth = (screen->x_res - scale_data[0])*4096/ScaleX;
            actheight = (screen->y_res-scale_data[1])*4096/ScaleY;
            
            if(scale_data[4] <= 0x1000 || scale_data[5] <= 0x1000) {
                if(actwidth >= screen->x_res) {
                    actwidth =  screen->x_res;
                }

                if(actheight >= screen->y_res) {
                    actheight = screen->y_res;
                }

                actwidth -= scale_data[2];
                actheight -= scale_data[3];
                
                //printk("Act: width: %d heitht: %d\n",actwidth,actheight);
                LcdMskReg(inf, WIN0_DSP_INFO, m_BIT11LO | m_BIT11HI,  v_BIT11LO(actwidth) | v_BIT11HI(actheight));
                LcdMskReg(inf, WIN0_SP_FACTOR_Y, m_WORDLO | m_WORDHI, v_WORDLO(ScaleX) | v_WORDHI(ScaleY));
                LcdMskReg(inf, WIN0_SD_FACTOR_Y, m_WORDLO | m_WORDHI, v_WORDLO(4096) | v_WORDHI(4096));
            } else {
                if((actwidth+scale_data[2]) > screen->x_res) {
                    actwidth -= (actwidth+scale_data[2]) - screen->x_res;
                }
                
                if((actheight+scale_data[3]) > screen->y_res) {
                    actheight -= (actheight+scale_data[3]) - screen->y_res;
                }

                //printk("Act: width: %d heitht: %d\n",actwidth,actheight);
                LcdMskReg(inf, WIN0_SP_FACTOR_Y, m_WORDLO | m_WORDHI, v_WORDLO(4096) | v_WORDHI(4096));
                LcdMskReg(inf, WIN0_SD_FACTOR_Y, m_WORDLO | m_WORDHI, v_WORDLO(ScaleX) | v_WORDHI(ScaleY));
                LcdMskReg(inf, WIN0_DSP_INFO, m_BIT11LO | m_BIT11HI,  v_BIT11LO(actwidth) | v_BIT11HI(actheight));
            } 
             
            LcdWrReg(inf, WIN0_YRGB_MST, vir_pos);
            LcdWrReg(inf, REG_CFG_DONE, 0x01);
        	pmem_scale_pos += 3;
            (*(pmem_st+SCALE_INFO_OFFSET+1))++;
        //} else if(*(pmem_st+SCALE_INFO_OFFSET+1) == *(pmem_st+SCALE_INFO_OFFSET)) {
        } else {    
            *(pmem_st+SCALE_INFO_OFFSET) = 0;
            *(pmem_st+SCALE_INFO_OFFSET+1) = 0;
            pmem_scale_pos = (int *)(pmem_st+2+SCALE_INFO_OFFSET);
        }
	}
}

void lcdc_soft_rst(void)
{
	volatile unsigned long *scu_softrst_con = (unsigned long *)(SCU_BASE_ADDR_VA + 40);

	*scu_softrst_con |= (1 << 1);  //reset
	udelay(10);
	*scu_softrst_con &= ~(1 << 1); //clean reset
}

int set_lcd_clk(int freq)
{
	printk("-----------------lcdc freq = %d------------\n", freq);
	
	switch(freq){
#ifdef CONFIG_ANX7150
	case HDMI_CLK_27M: // hmdi 576p, 27M
		//__rockchip_scu_set_parent(SCU_IPID_LCDC, SCU_IPID_ARM);
		__rockchip_clk_set_unit_clock(SCU_IPID_LCDC , 27);
		break;
	case HDMI_CLK_74M: // hdmi 720p, 74.25M
		//__rockchip_scu_set_parent(SCU_IPID_LCDC, SCU_IPID_ARM);
		__rockchip_clk_set_unit_clock(SCU_IPID_LCDC , 75);
		break;
#endif

#ifdef CONFIG_TV_RK1000
	case RK1000_TVOUT_CLK_27M: //cvbs pal, cvbs ntsc, Ypbpr 480, Ypbpr 576,     27M
        //__rockchip_scu_set_parent(SCU_IPID_LCDC, SCU_IPID_CODEC);
		__rockchip_clk_set_unit_clock(SCU_IPID_LCDC , 27);
		break;
	case RK1000_TVOUT_CLK_74M: // Ypbpr 720,     74.25M 
        //__rockchip_scu_set_parent(SCU_IPID_LCDC, SCU_IPID_CODEC);
		__rockchip_clk_set_unit_clock(SCU_IPID_LCDC , 75);
		break;
#endif

	default:
		if(freq > 0 && freq < 200){
			//__rockchip_scu_set_parent(SCU_IPID_LCDC, SCU_IPID_CODEC);
			__rockchip_clk_set_unit_clock(SCU_IPID_LCDC , freq);
		}
		else{
			printk("Invalid lcdc clk, freq=0x%08x\n", freq);
		}
		break;
	}

	return 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)
    {       
        GPIOSetPinDirection(lcd_cs, 1);
		GPIOSetPinLevel(lcd_cs, enable ? lcd_cs_pol : !lcd_cs_pol);
	}
    if(mach_info->gpio->display_on) 
    {
        
        GPIOSetPinDirection(display_on,1);
		GPIOSetPinLevel(display_on, enable ? display_on_pol : !display_on_pol);
    }
    if(mach_info->gpio->lcd_standby) 
    {
        
        GPIOSetPinDirection(lcd_standby, 1);
		GPIOSetPinLevel(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:
        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 = MS_IDLE;
        add_timer(&inf->mcutimer);
    }

    if(MS_MCU==inf->mcu_status)     mcu_do_refresh(inf);

    return 0;
}

int init_lcdc(struct fb_info *info)
{
    struct rk2818fb_inf *inf = info->device->driver_data;
    u32 reg1=0, reg2=0, msk=0, clr=0;

	fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__);

	// 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 = info->device->driver_data;
    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(0x000000) );

     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
	set_lcd_clk(screen->pixclock);

	//lcdc_soft_rst();
	//*inf->preg = inf->regbak;
	
    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 = info->device->driver_data;
    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 = info->device->driver_data;
    struct rk28fb_screen *cur_screen = inf->cur_screen;
	struct rk28fb_screen *lcd_info = &inf->lcd_info;

    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 = cur_screen->x_res;        //size of panel
    u16 ylcd = cur_screen->y_res;
    u16 yres = 0;

	printk("win0fb_check_var:\n");
	printk("cur_screen: x=%d, y=%d\n", cur_screen->x_res, cur_screen->y_res);
	printk("lcd       : x=%d, y=%d\n", lcd_info->x_res, lcd_info->y_res);
	printk("beforescal: (%d, %d)-(%d, %d)\n", xpos, ypos, xsize, ysize);

	/* scale */
	xpos = (xpos * cur_screen->x_res) / lcd_info->x_res;
	ypos = (ypos * cur_screen->y_res) / lcd_info->y_res;
	xsize = (xsize * cur_screen->x_res) / lcd_info->x_res;
	ysize = (ysize * cur_screen->y_res) / lcd_info->y_res;

	printk("after scal: (%d, %d)-(%d, %d)\n", xpos, ypos, xsize, ysize);
	
    if(IsMcuLandscape()) 
    {
        xlcd = cur_screen->y_res;
        ylcd = cur_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&0x0f)
    {
    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;
        }
        var->nonstd &= ~0xc0;  //not support I2P in this format
        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);
        var->nonstd &= ~0xc0;   //not support I2P in this format
        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);
        var->nonstd &= ~0xc0;   //not support I2P in this format
        break;
    case 5: // yuv444
        var->xres_virtual = (var->xres_virtual + 0x3) & (~0x3);
        var->xres = (var->xres + 0x3) & (~0x3);
        var->xoffset = (var->xoffset) & (~0x3);
        var->nonstd &= ~0xc0;   //not support I2P in this format
        break;
    default:
        printk(">>>>>> win0fb var->nonstd=%d is invalid! \n", var->nonstd);
        return -EINVAL;
    }

    if(var->rotate == 270)
    {
        yres = var->xres;
    }
    else
    {
        yres = var->yres;
    }
    ScaleYDnY = CalScaleDownW0(yres, ysize);
    ScaleYUpY = CalScaleUpW0(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 = info->device->driver_data;
    struct rk28fb_screen *cur_screen = inf->cur_screen;
	struct rk28fb_screen *lcd_info = &inf->lcd_info;
    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, i2p_len=0;
    u32 pre_y_addr = 0, pre_uv_addr = 0, nxt_y_addr = 0, nxt_uv_addr = 0;

    u32 actWidth = 0; 
    u32 actHeight = 0;     

	u32 xact = var->xres;			    /* visible resolution		*/
	u32 yact = var->yres;
	u32 xvir = var->xres_virtual;		/* virtual resolution		*/
	u32 yvir = var->yres_virtual;
	u32 xact_st = var->xoffset;			/* offset from virtual to visible */
	u32 yact_st = var->yoffset;			/* resolution			*/

    u16 xpos = (var->nonstd>>8) & 0xfff;      //visiable pos in panel
    u16 ypos = (var->nonstd>>20) & 0xfff;
    u16 xsize = (var->grayscale>>8) & 0xfff;  //visiable size in panel
    u16 ysize = (var->grayscale>>20) & 0xfff;

    u32 ScaleYUpX=0x1000, ScaleYDnX=0x1000, ScaleYUpY=0x1000, ScaleYDnY=0x1000;
    u32 ScaleCbrUpX=0x1000, ScaleCbrDnX=0x1000, ScaleCbrUpY=0x1000, ScaleCbrDnY=0x1000;

    u8 i2p_mode = (var->nonstd & 0x80)>>7;
    u8 i2p_polarity = (var->nonstd & 0x40)>>6;
    u8 data_format = var->nonstd&0x0f;
    u32 win0_en = var->reserved[2];
    u32 y_addr = var->reserved[3];       //user alloc buf addr y
    u32 uv_addr = var->reserved[4];    
    
    fbprintk(">>>>>> %s : %s\n", __FILE__, __FUNCTION__);

    fbprintk("win0_en = %x, y_addr = %8x, uv_addr = %8x\n", win0_en, y_addr, uv_addr);

	/* scale */
	xpos = (xpos * cur_screen->x_res) / lcd_info->x_res;
	ypos = (ypos * cur_screen->y_res) / lcd_info->y_res;
	xsize = (xsize * cur_screen->x_res) / lcd_info->x_res;
	ysize = (ysize * cur_screen->y_res) / lcd_info->y_res;

	CHK_SUSPEND(inf);

	/* calculate y_offset,uv_offset,line_length,cblen and crlen  */
    switch (data_format)
    {
    case 0: // rgb
        switch(var->bits_per_pixel)
        {
        case 16:    // rgb565
            format = 1;
            fix->line_length = 2 * xvir;
            y_offset = (yact_st*xvir + xact_st)*2;
            break;
        case 32:    // rgb888
            format = 0;
            fix->line_length = 4 * xvir;
            y_offset = (yact_st*xvir + xact_st)*4;
            break;
        default:
            return -EINVAL;
        }
        break;
    case 1: // yuv422
        format = 2;
        fix->line_length = xvir;     
        y_offset = yact_st*xvir + xact_st;
        uv_offset = yact_st*xvir + xact_st;
        if(var->rotate == 270)
        {
            y_offset += xvir*(yact- 1);
            uv_offset += xvir*(yact - 1);
        }
        cblen = crlen = (xvir*yvir)/2;
        if(i2p_mode)
        {
            i2p_len = (xvir*yvir)*2;
        }
        break;
    case 2: // yuv4200
        format = 3;
        fix->line_length = xvir;
        y_offset = yact_st*xvir + xact_st;
        uv_offset = (yact_st/2)*xvir + xact_st;
        if(var->rotate == 270)
        {
            y_offset += xvir*(yact - 1);
            uv_offset += xvir*(yact/2 - 1);
        }
        cblen = crlen = (xvir*yvir)/4;
        if(i2p_mode)
        {
            i2p_len = (xvir*yvir)*3/2;
        }
        break;
    case 3: // yuv4201
        format = 4;
        fix->line_length = xvir;
        y_offset = (yact_st/2)*2*xvir + (xact_st)*2;
        uv_offset = (yact_st/2)*xvir + xact_st;
        if(var->rotate == 270)
        {
            y_offset += xvir*2*(yact/2 - 1);
            uv_offset += xvir*(yact/2 - 1);
        }
        cblen = crlen = (xvir*yvir)/4;
        break;
    case 4: // yuv420m
        format = 5;
        fix->line_length = xvir;
        y_offset = (yact_st/2)*3*xvir + (xact_st)*3;
        cblen = crlen = (xvir*yvir)/4;
        break;
    case 5: // yuv444
        format = 6;
        fix->line_length = xvir;
        y_offset = yact_st*xvir + xact_st;
        uv_offset = yact_st*2*xvir + xact_st*2;
        cblen = crlen = (xvir*yvir);
        break;
    default:
        return -EINVAL;
    }

    smem_len = fix->line_length * yvir + cblen + crlen + i2p_len;
    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;
        fbprintk("buffer alloced by user fix->smem_start = %x, fix->smem_len = %8x, fix->mmio_start = %8x \n", fix->smem_start, fix->smem_len, fix->mmio_start);
    }
    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 + %d\n", smem_len, fix->line_length, yvir, cblen, crlen, i2p_len);
            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;
                fix->reserved[1] = 0;
                fix->reserved[2] = 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 * yvir;
            if(i2p_len)
            {
                fix->reserved[1] = fix->mmio_start + cblen + crlen;       //next frame buf Y address in i2p mode               
                fix->reserved[2] = fix->reserved[1] + fix->line_length * yvir;  //next frame buf UV address in i2p mode  
            }   
            else
            {
                fix->reserved[1] = fix->reserved[2] = 0;
            }
            fbprintk(">>>>>> alloc succ, smem_start=%08x, smem_len=%d, mmio_start=%08x!\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
    
    if(i2p_mode && fix->reserved[1] && fix->reserved[2])
    {           
        if(i2p_polarity && (var->rotate==0)) //even
        {                    
            y_addr = fix->smem_start + (yact_st*xvir+xact_st) + xvir;
            uv_addr = fix->mmio_start + (yact_st/data_format*xvir+xact_st) + xvir;
            pre_y_addr = y_addr - xvir;
            pre_uv_addr = uv_addr - xvir;                     
            nxt_y_addr = fix->reserved[1] + (yact_st*xvir+xact_st); 
            nxt_uv_addr = fix->reserved[2] + (yact_st/data_format*xvir+xact_st);
        }
        else if(!i2p_polarity && (var->rotate==0))  //odd
        {                                        
             y_addr =  fix->smem_start + (yact_st*xvir+xact_st);
             uv_addr = fix->mmio_start + (yact_st/data_format*xvir+xact_st);
             pre_y_addr = y_addr + xvir;
             pre_uv_addr = uv_addr + xvir; 
             nxt_y_addr = fix->reserved[1] + (yact_st*xvir+xact_st) + xvir; 
             nxt_uv_addr = fix->reserved[2] + (yact_st/data_format*xvir+xact_st) + xvir; 
        }
        else if(i2p_polarity && (var->rotate==270))  //even
        {        
             y_addr = fix->smem_start+ (yact_st*xvir+xact_st) + xvir*(yact-1);
             uv_addr = fix->mmio_start+ (yact_st/data_format*xvir+xact_st) + xvir*(yact/data_format-1);
             pre_y_addr = fix->smem_start+ (yact_st*xvir+xact_st) + xvir*(yact-2);
             pre_uv_addr = fix->mmio_start+ (yact_st/data_format*xvir+xact_st) + xvir*(yact/data_format-2);                     
             nxt_y_addr = fix->reserved[1] + (yact_st*xvir+xact_st) + xvir*(yact-2); 
             nxt_uv_addr = fix->reserved[2] + (yact_st/data_format*xvir+xact_st) + xvir*(yact/data_format-2); 
        }
        else if(!i2p_polarity&& (var->rotate==270))  //odd
        {        
             y_addr = fix->smem_start + (yact_st*xvir+xact_st) + xvir*(yact-2);
             uv_addr = fix->mmio_start  + (yact_st/data_format*xvir+xact_st) + xvir*(yact/data_format-2);
             pre_y_addr = fix->smem_start + (yact_st*xvir+xact_st) + xvir*(yact-1);
             pre_uv_addr = fix->mmio_start + (yact_st/data_format*xvir+xact_st) + xvir*(yact/data_format-1);                     
             nxt_y_addr =  fix->reserved[1]+ (yact_st*xvir+xact_st) + xvir*(yact-1);
             nxt_uv_addr = fix->reserved[2] + (yact_st/data_format*xvir+xact_st) + xvir*(yact/data_format-1); 
        }               
    }
    else
    {        
        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->rotate == 270)
    {      
        actWidth = yact;
        actHeight = xact;
    }
    else
    {
        actWidth = xact;
        actHeight = yact; 
    }
    if((xact>1280) && (xsize>1280))
    {
        ScaleYDnX = CalScaleDownW0(actWidth, 1280);
        ScaleYUpX = CalScaleUpW0(1280, xsize);
    }
    else
    {
        ScaleYDnX = CalScaleDownW0(actWidth, xsize);
        ScaleYUpX = CalScaleUpW0(actWidth, xsize);
    }

    ScaleYDnY = CalScaleDownW0(actHeight, ysize);
    ScaleYUpY = CalScaleUpW0(actHeight, ysize);

    switch (data_format)
    {       
       case 1:// yuv422
           if((xact>1280) && (xsize>1280))
           {
               ScaleCbrDnX= CalScaleDownW0((actWidth/2), 1280);   
               ScaleCbrUpX = CalScaleUpW0((640), xsize); 
           }
           else             
           {
               if(var->rotate == 270) 
               {
                   ScaleCbrDnX= CalScaleDownW0(actWidth, xsize);   
                   ScaleCbrUpX = CalScaleUpW0(actWidth, xsize); 
               }
               else
               {
                   ScaleCbrDnX= CalScaleDownW0((actWidth/2), xsize);   
                   ScaleCbrUpX = CalScaleUpW0((actWidth/2), xsize);   
               }
           }        
           
           ScaleCbrDnY =  CalScaleDownW0(actHeight, ysize);  
           ScaleCbrUpY =  CalScaleUpW0(actHeight, ysize); 
           break;
       case 2: // yuv4200
       case 3: // yuv4201
       case 4: // yuv420m                   
           if((xact>1280) && (xsize>1280))
           {
               ScaleCbrDnX= CalScaleDownW0(actWidth/2, 1280);   
               ScaleCbrUpX = CalScaleUpW0(640, xsize); 
           }
           else
           {
               ScaleCbrDnX= CalScaleDownW0(actWidth/2, xsize);   
               ScaleCbrUpX = CalScaleUpW0(actWidth/2, xsize); 
           }
           
           ScaleCbrDnY =  CalScaleDownW0(actHeight/2, ysize);  
           ScaleCbrUpY =  CalScaleUpW0(actHeight/2, ysize);  
           break;
       case 5:// yuv444
           if((xact>1280) && (xsize>1280))
           {
               ScaleCbrDnX= CalScaleDownW0(actWidth, 1280);   
               ScaleCbrUpX = CalScaleUpW0(1280, xsize);   
           }
           else
           {
               ScaleCbrDnX= CalScaleDownW0(actWidth, xsize);   
               ScaleCbrUpX = CalScaleUpW0(actWidth, xsize); 
           }
           ScaleCbrDnY =  CalScaleDownW0(actHeight, ysize);  
           ScaleCbrUpY =  CalScaleUpW0(actHeight, ysize);    
           break;
    }
        
    xpos += (cur_screen->left_margin + cur_screen->hsync_len);
    ypos += (cur_screen->upper_margin + cur_screen->vsync_len);

    LcdWrReg(inf, WIN0_YRGB_MST, y_addr);
    LcdWrReg(inf, WIN0_CBR_MST, uv_addr);
    LcdWrReg(inf, WIN0_YRGB_VIR_MST, fix->smem_start);
    LcdWrReg(inf, WIN0_CBR_VIR_MST, fix->mmio_start);

    LcdMskReg(inf, SYS_CONFIG, m_W0_ENABLE | m_W0_FORMAT | m_W0_ROTATE | m_MPEG2_I2P_EN,
        v_W0_ENABLE(win0_en) | v_W0_FORMAT(format) | v_W0_ROTATE(var->rotate==270) | v_MPEG2_I2P_EN(i2p_mode));
    
    LcdMskReg(inf, WIN0_VIR, m_WORDLO | m_WORDHI, v_VIRWIDTH(xvir) | v_VIRHEIGHT((yvir)) );
    LcdMskReg(inf, WIN0_ACT_INFO, m_WORDLO | m_WORDHI, v_WORDLO(actWidth) | v_WORDHI(actHeight));
    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(i2p_polarity) | v_DROP_LINE_W0(0));

    LcdWrReg(inf, I2P_REF0_MST_Y, pre_y_addr);
    LcdWrReg(inf, I2P_REF0_MST_CBR, pre_uv_addr);
    LcdWrReg(inf, I2P_REF1_MST_Y, nxt_y_addr);
    LcdWrReg(inf, I2P_REF1_MST_CBR, nxt_uv_addr);
        
    switch(format)
    {   
    case 1:  //rgb565
        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 4:   //yuv4201
        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 = info->device->driver_data;
    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&0x0f)
    {
    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;
    if(testflag)
    {
         return 0;
    }

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

/* Set rotation (0, 90, 180, 270 degree), and switch to the new mode. */
int win0fb_rotate(struct fb_info *fbi, int rotate)
{
    struct fb_var_screeninfo *var = &fbi->var;
    u32 SrcFmt = var->nonstd&0x0f;

    fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__);
    
    if(rotate == 0)
    {
        if(var->rotate)
        {
           var->rotate = 0; 
           if(!win0fb_check_var(var, fbi))
              win0fb_set_par(fbi);
        }        
    }
    else
    {
        if((var->xres >1280) || (var->yres >720)||((SrcFmt!= 1) && (SrcFmt!= 2) && (SrcFmt!= 3)))
        {
            return -EPERM;
        }  
        if(var->rotate != 270)
        {
            var->rotate = 270;
            if(!win0fb_check_var(var, fbi))
               win0fb_set_par(fbi);
        }
    }
    
    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;
	info->var.reserved[2] = 0;
	info->var.reserved[3] = -1;	
	info->var.reserved[4] = -1;

    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 = info->device->driver_data;
    struct fb_var_screeninfo *var0 = &info->var;
    struct fb_fix_screeninfo *fix0 = &info->fix;
    struct win0_par *par = info->par;
    struct rk28fb_screen *screen = inf->cur_screen;
    void __user *argp = (void __user *)arg;

	fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__);
    fbprintk("win0fb_ioctl cmd = %8x, arg = %8x \n", cmd, arg);
    
	CHK_SUSPEND(inf);

    switch(cmd)
    {
    case FB1_IOCTL_GET_PANEL_SIZE:    //get panel size
        {
            u32 panel_size[2];
            if(IsMcuLandscape()) {
                panel_size[0] = inf->lcd_info.y_res;
                panel_size[1] = inf->lcd_info.x_res;
            } else {
                panel_size[0] = inf->lcd_info.x_res;
                panel_size[1] = inf->lcd_info.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;

            fbprintk("yuv_phy[0] = %8x, yuv_phy[1] = %8x, par->y_offset, par->uv_offset \n", yuv_phy[0], yuv_phy[1], par->y_offset, par->uv_offset);

            yuv_phy[0] += par->y_offset;
            yuv_phy[1] += par->uv_offset;
			info->var.reserved[3] = yuv_phy[0];	
			info->var.reserved[4] = yuv_phy[1];
            if(testflag)
            {
                break;
            }
           // printk("new y_addr=%08x, new uv_addr=%08x ,par->y_offet: %p\n", yuv_phy[0], yuv_phy[1],par->y_offset);
            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_IOCTL_SCALE:  //scale the active screen or set display pos on display screen
        {
            u32 yuv_phy[6];
            u32 ScaleX,ScaleY;
            u32 dsp_posx,dsp_posy;
            u32 actwidth,actheight;
            u32 vir_pos;
            
            if(copy_from_user(yuv_phy, argp, 24))
                return -EFAULT;

            ScaleX=yuv_phy[4];
            ScaleY=yuv_phy[5];

            dsp_posx = yuv_phy[2] + (screen->left_margin + screen->hsync_len);
            dsp_posy = yuv_phy[3] + (screen->upper_margin + screen->vsync_len);
            
            vir_pos = par->y_offset+(yuv_phy[0]+yuv_phy[1]*var0->xres_virtual)*2+LcdRdReg(inf,WIN0_YRGB_VIR_MST);
            
            LcdMskReg(inf, WIN0_DSP_ST, m_BIT11LO | m_BIT11HI, v_BIT11LO(dsp_posx) | v_BIT11HI(dsp_posy));
            
            actwidth = (screen->x_res - yuv_phy[0])*4096/ScaleX;
            actheight = (screen->y_res-yuv_phy[1])*4096/ScaleY;
            
            if(yuv_phy[4] <= 0x1000 || yuv_phy[5] <= 0x1000) {
                if(actwidth >= screen->x_res) {
                    actwidth =  screen->x_res;
                }

                if(actheight >= screen->y_res) {
                    actheight = screen->y_res;
                }

                actwidth -= yuv_phy[2];
                actheight -= yuv_phy[3];
                
                //printk("Act: width: %d heitht: %d\n",actwidth,actheight);
                LcdMskReg(inf, WIN0_DSP_INFO, m_BIT11LO | m_BIT11HI,  v_BIT11LO(actwidth) | v_BIT11HI(actheight));
                LcdMskReg(inf, WIN0_SP_FACTOR_Y, m_WORDLO | m_WORDHI, v_WORDLO(ScaleX) | v_WORDHI(ScaleY));
                LcdMskReg(inf, WIN0_SD_FACTOR_Y, m_WORDLO | m_WORDHI, v_WORDLO(4096) | v_WORDHI(4096));
            } else {
                if((actwidth+yuv_phy[2]) > screen->x_res) {
                    actwidth -= (actwidth+yuv_phy[2]) - screen->x_res;
                }
                
                if((actheight+yuv_phy[3]) > screen->y_res) {
                    actheight -= (actheight+yuv_phy[3]) - screen->y_res;
                }

                //printk("Act: width: %d heitht: %d\n",actwidth,actheight);
                LcdMskReg(inf, WIN0_SP_FACTOR_Y, m_WORDLO | m_WORDHI, v_WORDLO(4096) | v_WORDHI(4096));
                LcdMskReg(inf, WIN0_SD_FACTOR_Y, m_WORDLO | m_WORDHI, v_WORDLO(ScaleX) | v_WORDHI(ScaleY));
                LcdMskReg(inf, WIN0_DSP_INFO, m_BIT11LO | m_BIT11HI,  v_BIT11LO(actwidth) | v_BIT11HI(actheight));
            } 
             
            LcdWrReg(inf, WIN0_YRGB_MST, vir_pos);
            LcdWrReg(inf, REG_CFG_DONE, 0x01);
        }
        break;

    case FB1_IOCTL_MOV_POS:    //scale the virtural screen
        { 
            u32 pos_inf;
            u32 data[2];
            u32 y_offset=0, y_addr=0;
            if(copy_from_user(&pos_inf,argp,4))
                return -EFAULT;

            data[0] = (pos_inf >> 16) & 0xffff;
            data[1] = pos_inf & 0x0000ffff;
            data[0] = data[0] & (~0x1);
            y_offset = par->y_offset+(data[1]*var0->xres_virtual + data[0])*2+LcdRdReg(inf,WIN0_YRGB_VIR_MST);
            printk("Mov_pos: %p \n",y_offset);
            LcdWrReg(inf, WIN0_YRGB_MST, y_offset);
            LcdWrReg(inf, REG_CFG_DONE, 0x01);
        }
        break;
    
    case FB1_IOCTL_FRAME_CTRL:
        { 
            u32 frame_status;
            if(copy_from_user(&frame_status,argp,4))
                return -EFAULT;
            printk("FRAME_CTRL------------------------------send_frame: %d \n",frame_status);
            send_frame=frame_status;
        }
        break;
    case FB1_IOCTL_VIR_ADDR_ST:
        {
            u32 data[4];
            if(copy_from_user(data,argp,16))
                return -EFAULT;
                
            printk("VIR_ADDR_ST: %p , %p , %p\n",data[0],data[1],data[2]);
            
            LcdWrReg(inf, WIN0_YRGB_VIR_MST, data[0]);
            //data[3] += par->y_offset;
	        LcdWrReg(inf, WIN0_YRGB_MST, data[3]);
            LcdMskReg(inf, WIN0_VIR, m_WORDLO | m_WORDHI, v_VIRWIDTH(data[1]) | v_VIRHEIGHT(data[2]) );
            LcdMskReg(inf, WIN0_ACT_INFO, m_WORDLO | m_WORDHI, v_WORDLO(screen->x_res) | v_WORDHI(screen->y_res));
            LcdMskReg(inf, SYS_CONFIG, m_W0_ENABLE | m_W0_FORMAT, v_W0_ENABLE(1)|v_W0_FORMAT(1));
            LcdWrReg(inf, REG_CFG_DONE, 0x01);
             // enable win0 after the win0 par is seted
            par->addr_seted = 1;
            //if(par->par_seted) { 
                mcu_refresh(inf);
            //}
        }
        break;

    case FB1_IOCTL_SET_CTRL_ADDR:
        {
            u32 ctrl_addr;
            if(copy_from_user(&ctrl_addr,argp,4))
                return -EFAULT;
            pmem_st = (int *)ioremap(ctrl_addr,0x19000);
            pmem_pos = (int *)(pmem_st+2);
            *(pmem_st+1) = 0;
            send_frame=1;
        }
        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;
    case FB1_IOCTL_SET_ROTATE:
        fbprintk(">>>>>> change lcdc direction(%d) \n", (int)arg);
        switch(arg)
        {
        case 0:
            win0fb_rotate(info, 0);
            break;
        case 270:
            win0fb_rotate(info, 270);
            break;
        }
        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 = info->device->driver_data;
    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 = info->device->driver_data;
    struct rk28fb_screen *cur_screen = inf->cur_screen;
	struct rk28fb_screen *lcd_info = &inf->lcd_info;
    u32 ScaleY = 0x1000;
    u16 xpos = (var->nonstd>>8) & 0xfff;
    u16 ypos = (var->nonstd>>20) & 0xfff;
    u16 xlcd = cur_screen->x_res;
    u16 ylcd = cur_screen->y_res;
    u8 trspmode = (var->grayscale>>8) & 0xff;
    u8 trspval = (var->grayscale) & 0xff;
    u16 xsize = var->xres;//(var->grayscale>>8) & 0xfff;    //visiable size in panel
    u16 ysize = var->yres;//(var->grayscale>>20) & 0xfff;   

    fbprintk(">>>>>> %s : %s\n", __FILE__, __FUNCTION__);

	/* scale */
	xpos = (xpos * cur_screen->x_res) / lcd_info->x_res;
	ypos = (ypos * cur_screen->y_res) / lcd_info->y_res;
	xsize = (xsize * cur_screen->x_res) / lcd_info->x_res;
	ysize = (ysize * cur_screen->y_res) / lcd_info->y_res;

	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+xsize)>xlcd || (ypos+ysize)>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,xsize,xlcd,ypos,ysize,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 = info->device->driver_data;
    struct fb_var_screeninfo *var = &info->var;
    struct fb_fix_screeninfo *fix = &info->fix;
    struct rk28fb_screen *cur_screen = inf->cur_screen;
	struct rk28fb_screen *lcd_info = &inf->lcd_info;
    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;
    u32 ScaleX = 0x1000;
    u32 ScaleY = 0x1000;

    u16 xres_virtual = var->xres_virtual;      //virtual screen size
   // u16 yres_virtual = var->yres_virtual;
    u16 xsize_virtual = var->xres;             //visiable size in virtual screen
    u16 ysize_virtual = var->yres;
   // u16 xpos_virtual = var->xoffset;           //visiable offset in virtual screen
   // u16 ypos_virtual = var->yoffset;
    
    u16 xpos = (var->nonstd>>8) & 0xfff;        //visiable offset in panel
    u16 ypos = (var->nonstd>>20) & 0xfff;
    u16 xsize = var->xres;//(var->grayscale>>8) & 0xfff;    //visiable size in panel
    u16 ysize = var->yres;//(var->grayscale>>20) & 0xfff;   
    u8 trspmode = TRSP_CLOSE;
    u8 trspval = 0;

    //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__);
	
	/* scale */
	xpos = (xpos * cur_screen->x_res) / lcd_info->x_res;
	ypos = (ypos * cur_screen->y_res) / lcd_info->y_res;
	xsize = (xsize * cur_screen->x_res) / lcd_info->x_res;
	ysize = (ysize * cur_screen->y_res) / lcd_info->y_res;


	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 + CURSOR_BUF_SIZE;   //cursor buf also alloc here
    map_size = PAGE_ALIGN(smem_len);

#if WIN1_USE_DOUBLE_BUF
    if( var->yres_virtual == 2*lcd_info->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);

        gwin1bufv = info->screen_base;   //zyw test
        gwin1bufp = map_dma;

        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;

    ScaleX = CalScaleW1(xsize_virtual, xsize);
    ScaleY = CalScaleW1(ysize_virtual, ysize);

    LcdMskReg(inf, SYS_CONFIG, m_W1_ENABLE|m_W1_FORMAT, v_W1_ENABLE(1)|v_W1_FORMAT(format));  

    xpos += (cur_screen->left_margin + cur_screen->hsync_len);
    ypos += (cur_screen->upper_margin + cur_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(xsize) | v_BIT11HI(ysize)); 

    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(xsize_virtual) | v_WORDHI(ysize_virtual));

    LcdMskReg(inf, WIN1_SCL_FACTOR, m_HSCALE_FACTOR | m_VSCALE_FACTOR, v_HSCALE_FACTOR(ScaleX) | v_VSCALE_FACTOR(ScaleY));

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

     // enable win1 color key and set the color to black(rgb=0)
    LcdMskReg(inf, WIN1_COLOR_KEY_CTRL, m_COLORKEY_EN | m_KEYCOLOR, v_COLORKEY_EN(1) | v_KEYCOLOR(0));    
    
    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 = info->device->driver_data;
    struct fb_var_screeninfo *var1 = &info->var;
    struct fb_fix_screeninfo *fix1 = &info->fix;
    u32 offset = 0, addr = 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",(u32)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 = info->device->driver_data;
    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;
		//Display Blank, hs/vs/den output disable
		//LcdMskReg(inf, DSP_CTRL1, m_BLANK_OUT, v_BLANK_OUT(1));
		//LcdWrReg(inf, REG_CFG_DONE, 0x01);
		
		if(inf->cur_screen)
		{
			if(inf->cur_screen->standby)	inf->cur_screen->standby(1);
		}
		
        /* 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;
        }
     
		if(arg != 0){
			win1fb_blank(FB_BLANK_NORMAL, inf->win1fb);
		}else{
			win1fb_blank(FB_BLANK_UNBLANK, inf->win1fb);
		}

		// 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) {
				GPIOSetPinLevel(mach_info->gpio->display_on,
					(0!=arg) ? !inf->cur_screen->pin_dispon : inf->cur_screen->pin_dispon);
				gpio_direction_output(mach_info->gpio->display_on, 0);
			}
		}

		load_screen(info, 1);

		if(inf->cur_screen)
		{
			if(inf->cur_screen->standby)	inf->cur_screen->standby(0);
		}

		// hs/vs/den output enable
		//LcdMskReg(inf, DSP_CTRL1, m_BLANK_OUT, v_BLANK_OUT(0));
		//LcdWrReg(inf, REG_CFG_DONE, 0x01);
		
		mcu_refresh(inf);
        break;
    default:
        break;
    }
    return 0;
}

int rk2818fb_set_cur_screen(int type)
{
	struct rk2818fb_inf *inf = platform_get_drvdata(g_pdev);
	struct fb_info *info = inf->win0fb;
    struct rk2818_fb_mach_info *mach_info = info->device->platform_data;

  	if(inf->cur_screen)
	{
		if(inf->cur_screen->standby)	
		   inf->cur_screen->standby(1);
	}

	/* Load the new device's param */
	switch(type){
	case 0: //lcd
		inf->cur_screen = &inf->lcd_info;
		break;
	case 1: //tv ntsc cvbs
		inf->cur_screen = &inf->tv_info[0];
		break;
	case 2: //tv pal cvbs
		inf->cur_screen = &inf->tv_info[1];
		break;
	case 3: //tv 480 ypbpr
		inf->cur_screen = &inf->tv_info[2];
		break;
	case 4: //tv 576 ypbpr
		inf->cur_screen = &inf->tv_info[3];
		break;
	case 5: //tv 720 ypbpr
		inf->cur_screen = &inf->tv_info[4];
		break;
	case 6: //hdmi 720p@60HZ
		inf->cur_screen = &inf->hdmi_info[0];
		break;
	case 7: //hdmi 720p@50HZ
		inf->cur_screen = &inf->hdmi_info[1];
		break;
	case 8: //hdmi 576p@50HZ
		inf->cur_screen = &inf->hdmi_info[2];
		break;
	default:
		return -EINVAL;
	}

	// 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) {
			GPIOSetPinLevel(mach_info->gpio->display_on,
				(0!=type) ? !inf->cur_screen->pin_dispon : inf->cur_screen->pin_dispon);
			gpio_direction_output(mach_info->gpio->display_on, 0);
		}
	}

	load_screen(info, 1);

	if(inf->cur_screen){
		if(inf->cur_screen->standby)
			inf->cur_screen->standby(0);
	}

	mcu_refresh(inf);
}


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      = rk2818_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__);
	
	/* pmem_dsp start size 0x6EA00000
	 * pmem_st-4 = 0x6FEE7000
	 * pmem_pos = 0x6FEE7008
	 */ 

    schedule_delayed_work(&frame_delay_work,1);
    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;
	 int *reg = (int *)(SCU_BASE_ADDR_VA);   

/*------------------back light-----------------------
    rockchip_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));
	ret = fb_alloc_cmap(&inf->win1fb->cmap, 256, 0);
	if (ret < 0)
		goto release_cmap;

    /* 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);
    
	fbprintk("got 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");  
            rockchip_mux_api_set(mach_info->iomux->data24, 1);        
        } 
        else 
        {
            rockchip_mux_api_set(mach_info->iomux->data18, 1);
        }        
        rockchip_mux_api_set(mach_info->iomux->den, 1);
        rockchip_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) \n");
    ret = register_framebuffer(inf->win1fb);
    if(ret<0) 
    {
        printk(">> win1fb register_framebuffer fail!\n");
        ret = -EINVAL;
		goto release_win0fb;
    }
    
    fbprintk(">> Register framebuffer(win0fb) \n");

    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= ANDROID_EARLY_SUSPEND_LEVEL_DISABLE_FB;
    android_register_early_suspend(&inf->early_suspend);
#endif
    
    /*
     * pmem-dsp 21<<20
     * 1.ioremap last 100k region
     * 2.init a work queue to set address.
     * 3.make sure the initialize work befor
     * we request a lcdc irq.
     */
    /*
    pmem_st = (int *)ioremap(0x6FEE7000,0x19000);
    pmem_pos = (int *)(pmem_st+2);
    *(pmem_st+1) = 0;
    */
    INIT_DELAYED_WORK(&frame_delay_work, frame_do_work);

    /* 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 unregister_win1fb;
    }
    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))
    {
      //  rockchip_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;
        }
    }
 
    printk(" %s ok\n", __FUNCTION__);
    
    return ret;

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_cmap:
    if(&inf->win1fb->cmap)
        fb_dealloc_cmap(&inf->win1fb->cmap);
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;
    }

	
    
    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);
    	             //   rockchip_scu_disableclk( SCU_IPID_LCDC );
		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");
                   // rockchip_scu_enableclk( SCU_IPID_LCDC );
        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)
{
#if 0
    struct rk2818fb_inf *inf = platform_get_drvdata(pdev);
    mdelay(300);
	//printk("----------------------------rk2818fb_shutdown----------------------------\n");
  	set_lcd_pin(pdev, 0);	 	
#else
     pm_message_t   pm={PM_EVENT_SLEEP};
     printk("%s:: shutdown lcdc\n" , __func__ );
     rk2818fb_suspend(pdev , pm );
	//printk("----------------------------rk28fb_shutdown----------------------------\n");
  	//set_lcd_pin(pdev, 0);
    	//rockchip_scu_disableclk(SCU_IPID_LCDC);
#endif
}

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

#ifdef FB_TEST
void fb_test(u8 enable)
{
     u8* buf = NULL;

     struct rk2818fb_inf *inf = platform_get_drvdata(g_pdev);
     struct rk28fb_screen *screen = inf->cur_screen;
      
     if(!gwin1bufv || !gwin1bufp)
     {
         printk(">>>>>> %s : %s kmalloc err\n", __FILE__, __FUNCTION__);
         return;
     }
     if(enable==1)
     {
         memset(gwin1bufv, 0, screen->x_res * screen->y_res);
         memset(gwin1bufv+screen->x_res * screen->y_res, 0, screen->x_res * screen->y_res);
         LcdWrReg(inf, WIN0_YRGB_MST, (u32)(gwin1bufp));
         LcdWrReg(inf, WIN0_CBR_MST, (u32)(gwin1bufp +screen->x_res * screen->y_res));
         LcdMskReg(inf, SYS_CONFIG, m_W1_ENABLE|m_W0_ENABLE,v_W0_ENABLE(1)| v_W1_ENABLE(0));  
         testflag = 1;
     }
     else if(enable==2)
     {
         //rest lcdc clk
         rockchip_scu_reset_unit( 1 );
         memcpy(inf->preg, &inf->regbak, 47*4);  //resume reg
         
     }
     else
     {
         LcdMskReg(inf, SYS_CONFIG, m_W1_ENABLE|m_W0_ENABLE, v_W1_ENABLE(1)|v_W0_ENABLE(0)); 
         testflag = 0;
     }
     
     LcdWrReg(inf, REG_CFG_DONE, 0x01);
     
}
#endif 

drivers\video\rk2818_fb.h
/* 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
#define FB1_IOCTL_SET_ROTATE            0x5004
#define FB1_IOCTL_SCALE                 0x5005
#define FB1_IOCTL_MOV_POS               0x5006
#define FB1_IOCTL_FRAME_CTRL            0x5007
#define FB1_IOCTL_VIR_ADDR_ST           0x5008
#define FB1_IOCTL_SET_CTRL_ADDR         0x5009

/********************************************************************
**                          Структура определения                                *
********************************************************************/
/* 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;

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

extern void __init rk2818_add_device_lcdc(void);
extern int mcu_ioctl(unsigned int cmd, unsigned long arg);

#endif 

video\rk2818_fb.c
/*
 * 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 <asm/arch/iomux.h>
#include <asm/arch/gpio.h>
#include <asm/arch/hardware.h>

#include <asm/arch/rk28_scu.h>

//#include <asm/uaccess.h>

#ifdef CONFIG_ANDROID_POWER
#include <linux/android_power.h>
#endif
#ifdef CONFIG_ANX7150
#include <asm/arch/anx7150.h>
#endif
#ifdef CONFIG_TV_RK1000
#include <asm/arch/rk1000_tv.h>
#endif

#include "./display/screen/screen.h"

#define FB_TEST                 1       

#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

#define CURSOR_BUF_SIZE         256      //RK2818 cursor need 256B buf
#if 0
	 #define fbprintk(msg...)	printk(msg);
#else
	#define fbprintk(msg...)
#endif

#if 0
	#define fbprintk2(msg...)	printk(msg);
#else
	#define fbprintk2(msg...)
#endif

#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
    struct clk      *clk_share_mem;   //lcdc share memory 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;

    char __iomem *cursor_base;   /* cursor Virtual address*/
    __u32 cursor_size;           /* Amount of ioremapped VRAM or 0 */ 
    unsigned long  cursor_start;

    struct rk28fb_screen lcd_info;
    struct rk28fb_screen tv_info[5];
    struct rk28fb_screen hdmi_info[3];
    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;

//zyw test for a7
u32 gwin1bufv = 0;
u32 gwin1bufp = 0;
u8 testflag=0;

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;
int* pmem_pos;
int* pmem_scale_pos;
int* pmem_st;
int send_frame=0;
struct delayed_work frame_delay_work;	
#define SCALE_INFO_OFFSET	0x3200

void frame_do_work(struct work_struct *work) {
    if(send_frame != 0) {
        struct rk2818fb_inf *inf = platform_get_drvdata(g_pdev);
        struct fb_var_screeninfo *var0;//= inf->win0fb->var;
        struct win0_par *par;// = inf->win0fb->par;
        struct fb_fix_screeninfo *fix0;// = inf->win0fb->fix;
        struct rk28fb_screen *screen;
        
        screen = inf->cur_screen;
        par = inf->win0fb->par;
        var0 = &(inf->win0fb->var);
        fix0 = &(inf->win0fb->fix);

        u32 pos_inf;
        u32 data[2];
        u32 y_offset=0, y_addr=0;
        
      	u32 scale_data[6];
        u32 ScaleX,ScaleY;
        u32 dsp_posx,dsp_posy;
        u32 actwidth,actheight;
        u32 vir_pos;
        u32 i, j;
        //printk("FRAMEINT:pmem_start= %d; status_value= %d pos= %p\n \n",*pmem_st,*(pmem_st+1),*(pmem_pos));
        if(*pmem_st == 0) {
                pmem_pos = (int *)(pmem_st+2);
                *(pmem_st+1)= 0;
        } else if(*(pmem_st+1) < *pmem_st) {
            data[0] = ((*pmem_pos >> 16) & 0xffff)&(~0x1);
            data[1] = *pmem_pos & 0x0000ffff;
            //data[0] = data[0] & (~0x1);
            y_offset = par->y_offset+(data[1]*var0->xres_virtual + data[0])*2+LcdRdReg(inf, WIN0_YRGB_VIR_MST);

            LcdWrReg(inf, WIN0_YRGB_MST, y_offset);
            LcdWrReg(inf, REG_CFG_DONE, 0x01);
            pmem_pos += 1;
            (*(pmem_st+1))++;
        }
        //printk("Scale addr: srcstatus: %d,deststatus %d\n",*(pmem_st+SCALE_INFO_OFFSET),*(pmem_st+1+SCALE_INFO_OFFSET));
		if(*(pmem_st+SCALE_INFO_OFFSET) == 0) {
	        pmem_scale_pos = (int *)(pmem_st+2+SCALE_INFO_OFFSET);
	        *(pmem_st+SCALE_INFO_OFFSET+1) = 0;
		} else if(*(pmem_st+SCALE_INFO_OFFSET+1) < *(pmem_st+SCALE_INFO_OFFSET)) {
			for( i=0, j=0; i<5; i+=2, j++) {
				scale_data[i] = (*(pmem_scale_pos+j) & 0xffff0000) >>16;
				scale_data[i+1] = *(pmem_scale_pos+j) & 0x0000ffff;
			}
            //printk("Factory: %d, %d, %d, %d, %d, %d",scale_data[0],scale_data[1],scale_data[2],scale_data[3],scale_data[4],scale_data[5]);
            ScaleX=scale_data[4];
            ScaleY=scale_data[5];
            dsp_posx = scale_data[2] + (screen->left_margin + screen->hsync_len);
            dsp_posy = scale_data[3] + (screen->upper_margin + screen->vsync_len);
            
            vir_pos = par->y_offset+(scale_data[0]+scale_data[1]*var0->xres_virtual)*2+LcdRdReg(inf,WIN0_YRGB_VIR_MST);
            
            LcdMskReg(inf, WIN0_DSP_ST, m_BIT11LO | m_BIT11HI, v_BIT11LO(dsp_posx) | v_BIT11HI(dsp_posy));
            
            actwidth = (screen->x_res - scale_data[0])*4096/ScaleX;
            actheight = (screen->y_res-scale_data[1])*4096/ScaleY;
            
            if(scale_data[4] <= 0x1000 || scale_data[5] <= 0x1000) {
                if(actwidth >= screen->x_res) {
                    actwidth =  screen->x_res;
                }

                if(actheight >= screen->y_res) {
                    actheight = screen->y_res;
                }

                actwidth -= scale_data[2];
                actheight -= scale_data[3];
                
                //printk("Act: width: %d heitht: %d\n",actwidth,actheight);
                LcdMskReg(inf, WIN0_DSP_INFO, m_BIT11LO | m_BIT11HI,  v_BIT11LO(actwidth) | v_BIT11HI(actheight));
                LcdMskReg(inf, WIN0_SP_FACTOR_Y, m_WORDLO | m_WORDHI, v_WORDLO(ScaleX) | v_WORDHI(ScaleY));
                LcdMskReg(inf, WIN0_SD_FACTOR_Y, m_WORDLO | m_WORDHI, v_WORDLO(4096) | v_WORDHI(4096));
            } else {
                if((actwidth+scale_data[2]) > screen->x_res) {
                    actwidth -= (actwidth+scale_data[2]) - screen->x_res;
                }
                
                if((actheight+scale_data[3]) > screen->y_res) {
                    actheight -= (actheight+scale_data[3]) - screen->y_res;
                }

                //printk("Act: width: %d heitht: %d\n",actwidth,actheight);
                LcdMskReg(inf, WIN0_SP_FACTOR_Y, m_WORDLO | m_WORDHI, v_WORDLO(4096) | v_WORDHI(4096));
                LcdMskReg(inf, WIN0_SD_FACTOR_Y, m_WORDLO | m_WORDHI, v_WORDLO(ScaleX) | v_WORDHI(ScaleY));
                LcdMskReg(inf, WIN0_DSP_INFO, m_BIT11LO | m_BIT11HI,  v_BIT11LO(actwidth) | v_BIT11HI(actheight));
            } 
             
            LcdWrReg(inf, WIN0_YRGB_MST, vir_pos);
            LcdWrReg(inf, REG_CFG_DONE, 0x01);
        	pmem_scale_pos += 3;
            (*(pmem_st+SCALE_INFO_OFFSET+1))++;
        //} else if(*(pmem_st+SCALE_INFO_OFFSET+1) == *(pmem_st+SCALE_INFO_OFFSET)) {
        } else {    
            *(pmem_st+SCALE_INFO_OFFSET) = 0;
            *(pmem_st+SCALE_INFO_OFFSET+1) = 0;
            pmem_scale_pos = (int *)(pmem_st+2+SCALE_INFO_OFFSET);
        }
	}
}

void lcdc_soft_rst(void)
{
	volatile unsigned long *scu_softrst_con = (unsigned long *)(SCU_BASE_ADDR_VA + 40);

	*scu_softrst_con |= (1 << 1);  //reset
	udelay(10);
	*scu_softrst_con &= ~(1 << 1); //clean reset
}

int set_lcd_clk(int freq)
{
	printk("-----------------lcdc freq = %d------------\n", freq);
	
	switch(freq){
#ifdef CONFIG_ANX7150
	case HDMI_CLK_27M: // hmdi 576p, 27M
		//__rockchip_scu_set_parent(SCU_IPID_LCDC, SCU_IPID_ARM);
		__rockchip_clk_set_unit_clock(SCU_IPID_LCDC , 27);
		break;
	case HDMI_CLK_74M: // hdmi 720p, 74.25M
		//__rockchip_scu_set_parent(SCU_IPID_LCDC, SCU_IPID_ARM);
		__rockchip_clk_set_unit_clock(SCU_IPID_LCDC , 75);
		break;
#endif

#ifdef CONFIG_TV_RK1000
	case RK1000_TVOUT_CLK_27M: //cvbs pal, cvbs ntsc, Ypbpr 480, Ypbpr 576,     27M
        //__rockchip_scu_set_parent(SCU_IPID_LCDC, SCU_IPID_CODEC);
		__rockchip_clk_set_unit_clock(SCU_IPID_LCDC , 27);
		break;
	case RK1000_TVOUT_CLK_74M: // Ypbpr 720,     74.25M 
        //__rockchip_scu_set_parent(SCU_IPID_LCDC, SCU_IPID_CODEC);
		__rockchip_clk_set_unit_clock(SCU_IPID_LCDC , 75);
		break;
#endif

	default:
		if(freq > 0 && freq < 200){
			//__rockchip_scu_set_parent(SCU_IPID_LCDC, SCU_IPID_CODEC);
			__rockchip_clk_set_unit_clock(SCU_IPID_LCDC , freq);
		}
		else{
			printk("Invalid lcdc clk, freq=0x%08x\n", freq);
		}
		break;
	}

	return 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)
    {       
        GPIOSetPinDirection(lcd_cs, 1);
		GPIOSetPinLevel(lcd_cs, enable ? lcd_cs_pol : !lcd_cs_pol);
	}
    if(mach_info->gpio->display_on) 
    {
        
        GPIOSetPinDirection(display_on,1);
		GPIOSetPinLevel(display_on, enable ? display_on_pol : !display_on_pol);
    }
    if(mach_info->gpio->lcd_standby) 
    {
        
        GPIOSetPinDirection(lcd_standby, 1);
		GPIOSetPinLevel(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:
        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 = MS_IDLE;
        add_timer(&inf->mcutimer);
    }

    if(MS_MCU==inf->mcu_status)     mcu_do_refresh(inf);

    return 0;
}

int init_lcdc(struct fb_info *info)
{
    struct rk2818fb_inf *inf = info->device->driver_data;
    u32 reg1=0, reg2=0, msk=0, clr=0;

	fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__);

	// 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 = info->device->driver_data;
    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(0x000000) );

     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
	set_lcd_clk(screen->pixclock);

	//lcdc_soft_rst();
	//*inf->preg = inf->regbak;
	
    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 = info->device->driver_data;
    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 = info->device->driver_data;
    struct rk28fb_screen *cur_screen = inf->cur_screen;
	struct rk28fb_screen *lcd_info = &inf->lcd_info;

    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 = cur_screen->x_res;        //size of panel
    u16 ylcd = cur_screen->y_res;
    u16 yres = 0;

	printk("win0fb_check_var:\n");
	printk("cur_screen: x=%d, y=%d\n", cur_screen->x_res, cur_screen->y_res);
	printk("lcd       : x=%d, y=%d\n", lcd_info->x_res, lcd_info->y_res);
	printk("beforescal: (%d, %d)-(%d, %d)\n", xpos, ypos, xsize, ysize);

	/* scale */
	xpos = (xpos * cur_screen->x_res) / lcd_info->x_res;
	ypos = (ypos * cur_screen->y_res) / lcd_info->y_res;
	xsize = (xsize * cur_screen->x_res) / lcd_info->x_res;
	ysize = (ysize * cur_screen->y_res) / lcd_info->y_res;

	printk("after scal: (%d, %d)-(%d, %d)\n", xpos, ypos, xsize, ysize);
	
    if(IsMcuLandscape()) 
    {
        xlcd = cur_screen->y_res;
        ylcd = cur_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&0x0f)
    {
    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;
        }
        var->nonstd &= ~0xc0;  //not support I2P in this format
        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);
        var->nonstd &= ~0xc0;   //not support I2P in this format
        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);
        var->nonstd &= ~0xc0;   //not support I2P in this format
        break;
    case 5: // yuv444
        var->xres_virtual = (var->xres_virtual + 0x3) & (~0x3);
        var->xres = (var->xres + 0x3) & (~0x3);
        var->xoffset = (var->xoffset) & (~0x3);
        var->nonstd &= ~0xc0;   //not support I2P in this format
        break;
    default:
        printk(">>>>>> win0fb var->nonstd=%d is invalid! \n", var->nonstd);
        return -EINVAL;
    }

    if(var->rotate == 270)
    {
        yres = var->xres;
    }
    else
    {
        yres = var->yres;
    }
    ScaleYDnY = CalScaleDownW0(yres, ysize);
    ScaleYUpY = CalScaleUpW0(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 = info->device->driver_data;
    struct rk28fb_screen *cur_screen = inf->cur_screen;
	struct rk28fb_screen *lcd_info = &inf->lcd_info;
    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, i2p_len=0;
    u32 pre_y_addr = 0, pre_uv_addr = 0, nxt_y_addr = 0, nxt_uv_addr = 0;

    u32 actWidth = 0; 
    u32 actHeight = 0;     

	u32 xact = var->xres;			    /* visible resolution		*/
	u32 yact = var->yres;
	u32 xvir = var->xres_virtual;		/* virtual resolution		*/
	u32 yvir = var->yres_virtual;
	u32 xact_st = var->xoffset;			/* offset from virtual to visible */
	u32 yact_st = var->yoffset;			/* resolution			*/

    u16 xpos = (var->nonstd>>8) & 0xfff;      //visiable pos in panel
    u16 ypos = (var->nonstd>>20) & 0xfff;
    u16 xsize = (var->grayscale>>8) & 0xfff;  //visiable size in panel
    u16 ysize = (var->grayscale>>20) & 0xfff;

    u32 ScaleYUpX=0x1000, ScaleYDnX=0x1000, ScaleYUpY=0x1000, ScaleYDnY=0x1000;
    u32 ScaleCbrUpX=0x1000, ScaleCbrDnX=0x1000, ScaleCbrUpY=0x1000, ScaleCbrDnY=0x1000;

    u8 i2p_mode = (var->nonstd & 0x80)>>7;
    u8 i2p_polarity = (var->nonstd & 0x40)>>6;
    u8 data_format = var->nonstd&0x0f;
    u32 win0_en = var->reserved[2];
    u32 y_addr = var->reserved[3];       //user alloc buf addr y
    u32 uv_addr = var->reserved[4];    
    
    fbprintk(">>>>>> %s : %s\n", __FILE__, __FUNCTION__);

    fbprintk("win0_en = %x, y_addr = %8x, uv_addr = %8x\n", win0_en, y_addr, uv_addr);

	/* scale */
	xpos = (xpos * cur_screen->x_res) / lcd_info->x_res;
	ypos = (ypos * cur_screen->y_res) / lcd_info->y_res;
	xsize = (xsize * cur_screen->x_res) / lcd_info->x_res;
	ysize = (ysize * cur_screen->y_res) / lcd_info->y_res;

	CHK_SUSPEND(inf);

	/* calculate y_offset,uv_offset,line_length,cblen and crlen  */
    switch (data_format)
    {
    case 0: // rgb
        switch(var->bits_per_pixel)
        {
        case 16:    // rgb565
            format = 1;
            fix->line_length = 2 * xvir;
            y_offset = (yact_st*xvir + xact_st)*2;
            break;
        case 32:    // rgb888
            format = 0;
            fix->line_length = 4 * xvir;
            y_offset = (yact_st*xvir + xact_st)*4;
            break;
        default:
            return -EINVAL;
        }
        break;
    case 1: // yuv422
        format = 2;
        fix->line_length = xvir;     
        y_offset = yact_st*xvir + xact_st;
        uv_offset = yact_st*xvir + xact_st;
        if(var->rotate == 270)
        {
            y_offset += xvir*(yact- 1);
            uv_offset += xvir*(yact - 1);
        }
        cblen = crlen = (xvir*yvir)/2;
        if(i2p_mode)
        {
            i2p_len = (xvir*yvir)*2;
        }
        break;
    case 2: // yuv4200
        format = 3;
        fix->line_length = xvir;
        y_offset = yact_st*xvir + xact_st;
        uv_offset = (yact_st/2)*xvir + xact_st;
        if(var->rotate == 270)
        {
            y_offset += xvir*(yact - 1);
            uv_offset += xvir*(yact/2 - 1);
        }
        cblen = crlen = (xvir*yvir)/4;
        if(i2p_mode)
        {
            i2p_len = (xvir*yvir)*3/2;
        }
        break;
    case 3: // yuv4201
        format = 4;
        fix->line_length = xvir;
        y_offset = (yact_st/2)*2*xvir + (xact_st)*2;
        uv_offset = (yact_st/2)*xvir + xact_st;
        if(var->rotate == 270)
        {
            y_offset += xvir*2*(yact/2 - 1);
            uv_offset += xvir*(yact/2 - 1);
        }
        cblen = crlen = (xvir*yvir)/4;
        break;
    case 4: // yuv420m
        format = 5;
        fix->line_length = xvir;
        y_offset = (yact_st/2)*3*xvir + (xact_st)*3;
        cblen = crlen = (xvir*yvir)/4;
        break;
    case 5: // yuv444
        format = 6;
        fix->line_length = xvir;
        y_offset = yact_st*xvir + xact_st;
        uv_offset = yact_st*2*xvir + xact_st*2;
        cblen = crlen = (xvir*yvir);
        break;
    default:
        return -EINVAL;
    }

    smem_len = fix->line_length * yvir + cblen + crlen + i2p_len;
    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;
        fbprintk("buffer alloced by user fix->smem_start = %x, fix->smem_len = %8x, fix->mmio_start = %8x \n", fix->smem_start, fix->smem_len, fix->mmio_start);
    }
    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 + %d\n", smem_len, fix->line_length, yvir, cblen, crlen, i2p_len);
            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;
                fix->reserved[1] = 0;
                fix->reserved[2] = 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 * yvir;
            if(i2p_len)
            {
                fix->reserved[1] = fix->mmio_start + cblen + crlen;       //next frame buf Y address in i2p mode               
                fix->reserved[2] = fix->reserved[1] + fix->line_length * yvir;  //next frame buf UV address in i2p mode  
            }   
            else
            {
                fix->reserved[1] = fix->reserved[2] = 0;
            }
            fbprintk(">>>>>> alloc succ, smem_start=%08x, smem_len=%d, mmio_start=%08x!\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
    
    if(i2p_mode && fix->reserved[1] && fix->reserved[2])
    {           
        if(i2p_polarity && (var->rotate==0)) //even
        {                    
            y_addr = fix->smem_start + (yact_st*xvir+xact_st) + xvir;
            uv_addr = fix->mmio_start + (yact_st/data_format*xvir+xact_st) + xvir;
            pre_y_addr = y_addr - xvir;
            pre_uv_addr = uv_addr - xvir;                     
            nxt_y_addr = fix->reserved[1] + (yact_st*xvir+xact_st); 
            nxt_uv_addr = fix->reserved[2] + (yact_st/data_format*xvir+xact_st);
        }
        else if(!i2p_polarity && (var->rotate==0))  //odd
        {                                        
             y_addr =  fix->smem_start + (yact_st*xvir+xact_st);
             uv_addr = fix->mmio_start + (yact_st/data_format*xvir+xact_st);
             pre_y_addr = y_addr + xvir;
             pre_uv_addr = uv_addr + xvir; 
             nxt_y_addr = fix->reserved[1] + (yact_st*xvir+xact_st) + xvir; 
             nxt_uv_addr = fix->reserved[2] + (yact_st/data_format*xvir+xact_st) + xvir; 
        }
        else if(i2p_polarity && (var->rotate==270))  //even
        {        
             y_addr = fix->smem_start+ (yact_st*xvir+xact_st) + xvir*(yact-1);
             uv_addr = fix->mmio_start+ (yact_st/data_format*xvir+xact_st) + xvir*(yact/data_format-1);
             pre_y_addr = fix->smem_start+ (yact_st*xvir+xact_st) + xvir*(yact-2);
             pre_uv_addr = fix->mmio_start+ (yact_st/data_format*xvir+xact_st) + xvir*(yact/data_format-2);                     
             nxt_y_addr = fix->reserved[1] + (yact_st*xvir+xact_st) + xvir*(yact-2); 
             nxt_uv_addr = fix->reserved[2] + (yact_st/data_format*xvir+xact_st) + xvir*(yact/data_format-2); 
        }
        else if(!i2p_polarity&& (var->rotate==270))  //odd
        {        
             y_addr = fix->smem_start + (yact_st*xvir+xact_st) + xvir*(yact-2);
             uv_addr = fix->mmio_start  + (yact_st/data_format*xvir+xact_st) + xvir*(yact/data_format-2);
             pre_y_addr = fix->smem_start + (yact_st*xvir+xact_st) + xvir*(yact-1);
             pre_uv_addr = fix->mmio_start + (yact_st/data_format*xvir+xact_st) + xvir*(yact/data_format-1);                     
             nxt_y_addr =  fix->reserved[1]+ (yact_st*xvir+xact_st) + xvir*(yact-1);
             nxt_uv_addr = fix->reserved[2] + (yact_st/data_format*xvir+xact_st) + xvir*(yact/data_format-1); 
        }               
    }
    else
    {        
        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->rotate == 270)
    {      
        actWidth = yact;
        actHeight = xact;
    }
    else
    {
        actWidth = xact;
        actHeight = yact; 
    }
    if((xact>1280) && (xsize>1280))
    {
        ScaleYDnX = CalScaleDownW0(actWidth, 1280);
        ScaleYUpX = CalScaleUpW0(1280, xsize);
    }
    else
    {
        ScaleYDnX = CalScaleDownW0(actWidth, xsize);
        ScaleYUpX = CalScaleUpW0(actWidth, xsize);
    }

    ScaleYDnY = CalScaleDownW0(actHeight, ysize);
    ScaleYUpY = CalScaleUpW0(actHeight, ysize);

    switch (data_format)
    {       
       case 1:// yuv422
           if((xact>1280) && (xsize>1280))
           {
               ScaleCbrDnX= CalScaleDownW0((actWidth/2), 1280);   
               ScaleCbrUpX = CalScaleUpW0((640), xsize); 
           }
           else             
           {
               if(var->rotate == 270) 
               {
                   ScaleCbrDnX= CalScaleDownW0(actWidth, xsize);   
                   ScaleCbrUpX = CalScaleUpW0(actWidth, xsize); 
               }
               else
               {
                   ScaleCbrDnX= CalScaleDownW0((actWidth/2), xsize);   
                   ScaleCbrUpX = CalScaleUpW0((actWidth/2), xsize);   
               }
           }        
           
           ScaleCbrDnY =  CalScaleDownW0(actHeight, ysize);  
           ScaleCbrUpY =  CalScaleUpW0(actHeight, ysize); 
           break;
       case 2: // yuv4200
       case 3: // yuv4201
       case 4: // yuv420m                   
           if((xact>1280) && (xsize>1280))
           {
               ScaleCbrDnX= CalScaleDownW0(actWidth/2, 1280);   
               ScaleCbrUpX = CalScaleUpW0(640, xsize); 
           }
           else
           {
               ScaleCbrDnX= CalScaleDownW0(actWidth/2, xsize);   
               ScaleCbrUpX = CalScaleUpW0(actWidth/2, xsize); 
           }
           
           ScaleCbrDnY =  CalScaleDownW0(actHeight/2, ysize);  
           ScaleCbrUpY =  CalScaleUpW0(actHeight/2, ysize);  
           break;
       case 5:// yuv444
           if((xact>1280) && (xsize>1280))
           {
               ScaleCbrDnX= CalScaleDownW0(actWidth, 1280);   
               ScaleCbrUpX = CalScaleUpW0(1280, xsize);   
           }
           else
           {
               ScaleCbrDnX= CalScaleDownW0(actWidth, xsize);   
               ScaleCbrUpX = CalScaleUpW0(actWidth, xsize); 
           }
           ScaleCbrDnY =  CalScaleDownW0(actHeight, ysize);  
           ScaleCbrUpY =  CalScaleUpW0(actHeight, ysize);    
           break;
    }
        
    xpos += (cur_screen->left_margin + cur_screen->hsync_len);
    ypos += (cur_screen->upper_margin + cur_screen->vsync_len);

    LcdWrReg(inf, WIN0_YRGB_MST, y_addr);
    LcdWrReg(inf, WIN0_CBR_MST, uv_addr);
    LcdWrReg(inf, WIN0_YRGB_VIR_MST, fix->smem_start);
    LcdWrReg(inf, WIN0_CBR_VIR_MST, fix->mmio_start);

    LcdMskReg(inf, SYS_CONFIG, m_W0_ENABLE | m_W0_FORMAT | m_W0_ROTATE | m_MPEG2_I2P_EN,
        v_W0_ENABLE(win0_en) | v_W0_FORMAT(format) | v_W0_ROTATE(var->rotate==270) | v_MPEG2_I2P_EN(i2p_mode));
    
    LcdMskReg(inf, WIN0_VIR, m_WORDLO | m_WORDHI, v_VIRWIDTH(xvir) | v_VIRHEIGHT((yvir)) );
    LcdMskReg(inf, WIN0_ACT_INFO, m_WORDLO | m_WORDHI, v_WORDLO(actWidth) | v_WORDHI(actHeight));
    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(i2p_polarity) | v_DROP_LINE_W0(0));

    LcdWrReg(inf, I2P_REF0_MST_Y, pre_y_addr);
    LcdWrReg(inf, I2P_REF0_MST_CBR, pre_uv_addr);
    LcdWrReg(inf, I2P_REF1_MST_Y, nxt_y_addr);
    LcdWrReg(inf, I2P_REF1_MST_CBR, nxt_uv_addr);
        
    switch(format)
    {   
    case 1:  //rgb565
        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 4:   //yuv4201
        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 = info->device->driver_data;
    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&0x0f)
    {
    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;
    if(testflag)
    {
         return 0;
    }

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

/* Set rotation (0, 90, 180, 270 degree), and switch to the new mode. */
int win0fb_rotate(struct fb_info *fbi, int rotate)
{
    struct fb_var_screeninfo *var = &fbi->var;
    u32 SrcFmt = var->nonstd&0x0f;

    fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__);
    
    if(rotate == 0)
    {
        if(var->rotate)
        {
           var->rotate = 0; 
           if(!win0fb_check_var(var, fbi))
              win0fb_set_par(fbi);
        }        
    }
    else
    {
        if((var->xres >1280) || (var->yres >720)||((SrcFmt!= 1) && (SrcFmt!= 2) && (SrcFmt!= 3)))
        {
            return -EPERM;
        }  
        if(var->rotate != 270)
        {
            var->rotate = 270;
            if(!win0fb_check_var(var, fbi))
               win0fb_set_par(fbi);
        }
    }
    
    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;
	info->var.reserved[2] = 0;
	info->var.reserved[3] = -1;	
	info->var.reserved[4] = -1;

    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 = info->device->driver_data;
    struct fb_var_screeninfo *var0 = &info->var;
    struct fb_fix_screeninfo *fix0 = &info->fix;
    struct win0_par *par = info->par;
    struct rk28fb_screen *screen = inf->cur_screen;
    void __user *argp = (void __user *)arg;

	fbprintk(">>>>>> %s : %s \n", __FILE__, __FUNCTION__);
    fbprintk("win0fb_ioctl cmd = %8x, arg = %8x \n", cmd, arg);
    
	CHK_SUSPEND(inf);

    switch(cmd)
    {
    case FB1_IOCTL_GET_PANEL_SIZE:    //get panel size
        {
            u32 panel_size[2];
            if(IsMcuLandscape()) {
                panel_size[0] = inf->lcd_info.y_res;
                panel_size[1] = inf->lcd_info.x_res;
            } else {
                panel_size[0] = inf->lcd_info.x_res;
                panel_size[1] = inf->lcd_info.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;

            fbprintk("yuv_phy[0] = %8x, yuv_phy[1] = %8x, par->y_offset, par->uv_offset \n", yuv_phy[0], yuv_phy[1], par->y_offset, par->uv_offset);

            yuv_phy[0] += par->y_offset;
            yuv_phy[1] += par->uv_offset;
			info->var.reserved[3] = yuv_phy[0];	
			info->var.reserved[4] = yuv_phy[1];
            if(testflag)
            {
                break;
            }
           // printk("new y_addr=%08x, new uv_addr=%08x ,par->y_offet: %p\n", yuv_phy[0], yuv_phy[1],par->y_offset);
            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_IOCTL_SCALE:  //scale the active screen or set display pos on display screen
        {
            u32 yuv_phy[6];
            u32 ScaleX,ScaleY;
            u32 dsp_posx,dsp_posy;
            u32 actwidth,actheight;
            u32 vir_pos;
            
            if(copy_from_user(yuv_phy, argp, 24))
                return -EFAULT;

            ScaleX=yuv_phy[4];
            ScaleY=yuv_phy[5];

            dsp_posx = yuv_phy[2] + (screen->left_margin + screen->hsync_len);
            dsp_posy = yuv_phy[3] + (screen->upper_margin + screen->vsync_len);
            
            vir_pos = par->y_offset+(yuv_phy[0]+yuv_phy[1]*var0->xres_virtual)*2+LcdRdReg(inf,WIN0_YRGB_VIR_MST);
            
            LcdMskReg(inf, WIN0_DSP_ST, m_BIT11LO | m_BIT11HI, v_BIT11LO(dsp_posx) | v_BIT11HI(dsp_posy));
            
            actwidth = (screen->x_res - yuv_phy[0])*4096/ScaleX;
            actheight = (screen->y_res-yuv_phy[1])*4096/ScaleY;
            
            if(yuv_phy[4] <= 0x1000 || yuv_phy[5] <= 0x1000) {
                if(actwidth >= screen->x_res) {
                    actwidth =  screen->x_res;
                }

                if(actheight >= screen->y_res) {
                    actheight = screen->y_res;
                }

                actwidth -= yuv_phy[2];
                actheight -= yuv_phy[3];
                
                //printk("Act: width: %d heitht: %d\n",actwidth,actheight);
                LcdMskReg(inf, WIN0_DSP_INFO, m_BIT11LO | m_BIT11HI,  v_BIT11LO(actwidth) | v_BIT11HI(actheight));
                LcdMskReg(inf, WIN0_SP_FACTOR_Y, m_WORDLO | m_WORDHI, v_WORDLO(ScaleX) | v_WORDHI(ScaleY));
                LcdMskReg(inf, WIN0_SD_FACTOR_Y, m_WORDLO | m_WORDHI, v_WORDLO(4096) | v_WORDHI(4096));
            } else {
                if((actwidth+yuv_phy[2]) > screen->x_res) {
                    actwidth -= (actwidth+yuv_phy[2]) - screen->x_res;
                }
                
                if((actheight+yuv_phy[3]) > screen->y_res) {
                    actheight -= (actheight+yuv_phy[3]) - screen->y_res;
                }

                //printk("Act: width: %d heitht: %d\n",actwidth,actheight);
                LcdMskReg(inf, WIN0_SP_FACTOR_Y, m_WORDLO | m_WORDHI, v_WORDLO(4096) | v_WORDHI(4096));
                LcdMskReg(inf, WIN0_SD_FACTOR_Y, m_WORDLO | m_WORDHI, v_WORDLO(ScaleX) | v_WORDHI(ScaleY));
                LcdMskReg(inf, WIN0_DSP_INFO, m_BIT11LO | m_BIT11HI,  v_BIT11LO(actwidth) | v_BIT11HI(actheight));
            } 
             
            LcdWrReg(inf, WIN0_YRGB_MST, vir_pos);
            LcdWrReg(inf, REG_CFG_DONE, 0x01);
        }
        break;

    case FB1_IOCTL_MOV_POS:    //scale the virtural screen
        { 
            u32 pos_inf;
            u32 data[2];
            u32 y_offset=0, y_addr=0;
            if(copy_from_user(&pos_inf,argp,4))
                return -EFAULT;

            data[0] = (pos_inf >> 16) & 0xffff;
            data[1] = pos_inf & 0x0000ffff;
            data[0] = data[0] & (~0x1);
            y_offset = par->y_offset+(data[1]*var0->xres_virtual + data[0])*2+LcdRdReg(inf,WIN0_YRGB_VIR_MST);
            printk("Mov_pos: %p \n",y_offset);
            LcdWrReg(inf, WIN0_YRGB_MST, y_offset);
            LcdWrReg(inf, REG_CFG_DONE, 0x01);
        }
        break;
    
    case FB1_IOCTL_FRAME_CTRL:
        { 
            u32 frame_status;
            if(copy_from_user(&frame_status,argp,4))
                return -EFAULT;
            printk("FRAME_CTRL------------------------------send_frame: %d \n",frame_status);
            send_frame=frame_status;
        }
        break;
    case FB1_IOCTL_VIR_ADDR_ST:
        {
            u32 data[4];
            if(copy_from_user(data,argp,16))
                return -EFAULT;
                
            printk("VIR_ADDR_ST: %p , %p , %p\n",data[0],data[1],data[2]);
            
            LcdWrReg(inf, WIN0_YRGB_VIR_MST, data[0]);
            //data[3] += par->y_offset;
	        LcdWrReg(inf, WIN0_YRGB_MST, data[3]);
            LcdMskReg(inf, WIN0_VIR, m_WORDLO | m_WORDHI, v_VIRWIDTH(data[1]) | v_VIRHEIGHT(data[2]) );
            LcdMskReg(inf, WIN0_ACT_INFO, m_WORDLO | m_WORDHI, v_WORDLO(screen->x_res) | v_WORDHI(screen->y_res));
            LcdMskReg(inf, SYS_CONFIG, m_W0_ENABLE | m_W0_FORMAT, v_W0_ENABLE(1)|v_W0_FORMAT(1));
            LcdWrReg(inf, REG_CFG_DONE, 0x01);
             // enable win0 after the win0 par is seted
            par->addr_seted = 1;
            //if(par->par_seted) { 
                mcu_refresh(inf);
            //}
        }
        break;

    case FB1_IOCTL_SET_CTRL_ADDR:
        {
            u32 ctrl_addr;
            if(copy_from_user(&ctrl_addr,argp,4))
                return -EFAULT;
            pmem_st = (int *)ioremap(ctrl_addr,0x19000);
            pmem_pos = (int *)(pmem_st+2);
            *(pmem_st+1) = 0;
            send_frame=1;
        }
        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;
    case FB1_IOCTL_SET_ROTATE:
        fbprintk(">>>>>> change lcdc direction(%d) \n", (int)arg);
        switch(arg)
        {
        case 0:
            win0fb_rotate(info, 0);
            break;
        case 270:
            win0fb_rotate(info, 270);
            break;
        }
        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 = info->device->driver_data;
    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 = info->device->driver_data;
    struct rk28fb_screen *cur_screen = inf->cur_screen;
	struct rk28fb_screen *lcd_info = &inf->lcd_info;
    u32 ScaleY = 0x1000;
    u16 xpos = (var->nonstd>>8) & 0xfff;
    u16 ypos = (var->nonstd>>20) & 0xfff;
    u16 xlcd = cur_screen->x_res;
    u16 ylcd = cur_screen->y_res;
    u8 trspmode = (var->grayscale>>8) & 0xff;
    u8 trspval = (var->grayscale) & 0xff;
    u16 xsize = var->xres;//(var->grayscale>>8) & 0xfff;    //visiable size in panel
    u16 ysize = var->yres;//(var->grayscale>>20) & 0xfff;   

    fbprintk(">>>>>> %s : %s\n", __FILE__, __FUNCTION__);

	/* scale */
	xpos = (xpos * cur_screen->x_res) / lcd_info->x_res;
	ypos = (ypos * cur_screen->y_res) / lcd_info->y_res;
	xsize = (xsize * cur_screen->x_res) / lcd_info->x_res;
	ysize = (ysize * cur_screen->y_res) / lcd_info->y_res;

	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+xsize)>xlcd || (ypos+ysize)>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,xsize,xlcd,ypos,ysize,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 = info->device->driver_data;
    struct fb_var_screeninfo *var = &info->var;
    struct fb_fix_screeninfo *fix = &info->fix;
    struct rk28fb_screen *cur_screen = inf->cur_screen;
	struct rk28fb_screen *lcd_info = &inf->lcd_info;
    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;
    u32 ScaleX = 0x1000;
    u32 ScaleY = 0x1000;

    u16 xres_virtual = var->xres_virtual;      //virtual screen size
   // u16 yres_virtual = var->yres_virtual;
    u16 xsize_virtual = var->xres;             //visiable size in virtual screen
    u16 ysize_virtual = var->yres;
   // u16 xpos_virtual = var->xoffset;           //visiable offset in virtual screen
   // u16 ypos_virtual = var->yoffset;
    
    u16 xpos = (var->nonstd>>8) & 0xfff;        //visiable offset in panel
    u16 ypos = (var->nonstd>>20) & 0xfff;
    u16 xsize = var->xres;//(var->grayscale>>8) & 0xfff;    //visiable size in panel
    u16 ysize = var->yres;//(var->grayscale>>20) & 0xfff;   
    u8 trspmode = TRSP_CLOSE;
    u8 trspval = 0;

    //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__);
	
	/* scale */
	xpos = (xpos * cur_screen->x_res) / lcd_info->x_res;
	ypos = (ypos * cur_screen->y_res) / lcd_info->y_res;
	xsize = (xsize * cur_screen->x_res) / lcd_info->x_res;
	ysize = (ysize * cur_screen->y_res) / lcd_info->y_res;


	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 + CURSOR_BUF_SIZE;   //cursor buf also alloc here
    map_size = PAGE_ALIGN(smem_len);

#if WIN1_USE_DOUBLE_BUF
    if( var->yres_virtual == 2*lcd_info->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);

        gwin1bufv = info->screen_base;   //zyw test
        gwin1bufp = map_dma;

        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;

    ScaleX = CalScaleW1(xsize_virtual, xsize);
    ScaleY = CalScaleW1(ysize_virtual, ysize);

    LcdMskReg(inf, SYS_CONFIG, m_W1_ENABLE|m_W1_FORMAT, v_W1_ENABLE(1)|v_W1_FORMAT(format));  

    xpos += (cur_screen->left_margin + cur_screen->hsync_len);
    ypos += (cur_screen->upper_margin + cur_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(xsize) | v_BIT11HI(ysize)); 

    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(xsize_virtual) | v_WORDHI(ysize_virtual));

    LcdMskReg(inf, WIN1_SCL_FACTOR, m_HSCALE_FACTOR | m_VSCALE_FACTOR, v_HSCALE_FACTOR(ScaleX) | v_VSCALE_FACTOR(ScaleY));

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

     // enable win1 color key and set the color to black(rgb=0)
    LcdMskReg(inf, WIN1_COLOR_KEY_CTRL, m_COLORKEY_EN | m_KEYCOLOR, v_COLORKEY_EN(1) | v_KEYCOLOR(0));    
    
    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 = info->device->driver_data;
    struct fb_var_screeninfo *var1 = &info->var;
    struct fb_fix_screeninfo *fix1 = &info->fix;
    u32 offset = 0, addr = 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",(u32)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 = info->device->driver_data;
    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;
		//Display Blank, hs/vs/den output disable
		//LcdMskReg(inf, DSP_CTRL1, m_BLANK_OUT, v_BLANK_OUT(1));
		//LcdWrReg(inf, REG_CFG_DONE, 0x01);
		
		if(inf->cur_screen)
		{
			if(inf->cur_screen->standby)	inf->cur_screen->standby(1);
		}
		
        /* 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;
        }
     
		if(arg != 0){
			win1fb_blank(FB_BLANK_NORMAL, inf->win1fb);
		}else{
			win1fb_blank(FB_BLANK_UNBLANK, inf->win1fb);
		}

		// 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) {
				GPIOSetPinLevel(mach_info->gpio->display_on,
					(0!=arg) ? !inf->cur_screen->pin_dispon : inf->cur_screen->pin_dispon);
				gpio_direction_output(mach_info->gpio->display_on, 0);
			}
		}

		load_screen(info, 1);

		if(inf->cur_screen)
		{
			if(inf->cur_screen->standby)	inf->cur_screen->standby(0);
		}

		// hs/vs/den output enable
		//LcdMskReg(inf, DSP_CTRL1, m_BLANK_OUT, v_BLANK_OUT(0));
		//LcdWrReg(inf, REG_CFG_DONE, 0x01);
		
		mcu_refresh(inf);
        break;
    default:
        break;
    }
    return 0;
}

int rk2818fb_set_cur_screen(int type)
{
	struct rk2818fb_inf *inf = platform_get_drvdata(g_pdev);
	struct fb_info *info = inf->win0fb;
    struct rk2818_fb_mach_info *mach_info = info->device->platform_data;

  	if(inf->cur_screen)
	{
		if(inf->cur_screen->standby)	
		   inf->cur_screen->standby(1);
	}

	/* Load the new device's param */
	switch(type){
	case 0: //lcd
		inf->cur_screen = &inf->lcd_info;
		break;
	case 1: //tv ntsc cvbs
		inf->cur_screen = &inf->tv_info[0];
		break;
	case 2: //tv pal cvbs
		inf->cur_screen = &inf->tv_info[1];
		break;
	case 3: //tv 480 ypbpr
		inf->cur_screen = &inf->tv_info[2];
		break;
	case 4: //tv 576 ypbpr
		inf->cur_screen = &inf->tv_info[3];
		break;
	case 5: //tv 720 ypbpr
		inf->cur_screen = &inf->tv_info[4];
		break;
	case 6: //hdmi 720p@60HZ
		inf->cur_screen = &inf->hdmi_info[0];
		break;
	case 7: //hdmi 720p@50HZ
		inf->cur_screen = &inf->hdmi_info[1];
		break;
	case 8: //hdmi 576p@50HZ
		inf->cur_screen = &inf->hdmi_info[2];
		break;
	default:
		return -EINVAL;
	}

	// 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) {
			GPIOSetPinLevel(mach_info->gpio->display_on,
				(0!=type) ? !inf->cur_screen->pin_dispon : inf->cur_screen->pin_dispon);
			gpio_direction_output(mach_info->gpio->display_on, 0);
		}
	}

	load_screen(info, 1);

	if(inf->cur_screen){
		if(inf->cur_screen->standby)
			inf->cur_screen->standby(0);
	}

	mcu_refresh(inf);
}


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      = rk2818_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__);
	
	/* pmem_dsp start size 0x6EA00000
	 * pmem_st-4 = 0x6FEE7000
	 * pmem_pos = 0x6FEE7008
	 */ 

    schedule_delayed_work(&frame_delay_work,1);
    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;
	 int *reg = (int *)(SCU_BASE_ADDR_VA);   

/*------------------back light-----------------------
    rockchip_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));
	ret = fb_alloc_cmap(&inf->win1fb->cmap, 256, 0);
	if (ret < 0)
		goto release_cmap;

    /* 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);
    
	fbprintk("got 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");  
            rockchip_mux_api_set(mach_info->iomux->data24, 1);        
        } 
        else 
        {
            rockchip_mux_api_set(mach_info->iomux->data18, 1);
        }        
        rockchip_mux_api_set(mach_info->iomux->den, 1);
        rockchip_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) \n");
    ret = register_framebuffer(inf->win1fb);
    if(ret<0) 
    {
        printk(">> win1fb register_framebuffer fail!\n");
        ret = -EINVAL;
		goto release_win0fb;
    }
    
    fbprintk(">> Register framebuffer(win0fb) \n");

    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= ANDROID_EARLY_SUSPEND_LEVEL_DISABLE_FB;
    android_register_early_suspend(&inf->early_suspend);
#endif
    
    /*
     * pmem-dsp 21<<20
     * 1.ioremap last 100k region
     * 2.init a work queue to set address.
     * 3.make sure the initialize work befor
     * we request a lcdc irq.
     */
    /*
    pmem_st = (int *)ioremap(0x6FEE7000,0x19000);
    pmem_pos = (int *)(pmem_st+2);
    *(pmem_st+1) = 0;
    */
    INIT_DELAYED_WORK(&frame_delay_work, frame_do_work);

    /* 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 unregister_win1fb;
    }
    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))
    {
      //  rockchip_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;
        }
    }
 
    printk(" %s ok\n", __FUNCTION__);
    
    return ret;

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_cmap:
    if(&inf->win1fb->cmap)
        fb_dealloc_cmap(&inf->win1fb->cmap);
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;
    }

	
    
    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);
    	             //   rockchip_scu_disableclk( SCU_IPID_LCDC );
		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");
                   // rockchip_scu_enableclk( SCU_IPID_LCDC );
        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)
{
#if 0
    struct rk2818fb_inf *inf = platform_get_drvdata(pdev);
    mdelay(300);
	//printk("----------------------------rk2818fb_shutdown----------------------------\n");
  	set_lcd_pin(pdev, 0);	 	
#else
     pm_message_t   pm={PM_EVENT_SLEEP};
     printk("%s:: shutdown lcdc\n" , __func__ );
     rk2818fb_suspend(pdev , pm );
	//printk("----------------------------rk28fb_shutdown----------------------------\n");
  	//set_lcd_pin(pdev, 0);
    	//rockchip_scu_disableclk(SCU_IPID_LCDC);
#endif
}

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

#ifdef FB_TEST
void fb_test(u8 enable)
{
     u8* buf = NULL;

     struct rk2818fb_inf *inf = platform_get_drvdata(g_pdev);
     struct rk28fb_screen *screen = inf->cur_screen;
      
     if(!gwin1bufv || !gwin1bufp)
     {
         printk(">>>>>> %s : %s kmalloc err\n", __FILE__, __FUNCTION__);
         return;
     }
     if(enable==1)
     {
         memset(gwin1bufv, 0, screen->x_res * screen->y_res);
         memset(gwin1bufv+screen->x_res * screen->y_res, 0, screen->x_res * screen->y_res);
         LcdWrReg(inf, WIN0_YRGB_MST, (u32)(gwin1bufp));
         LcdWrReg(inf, WIN0_CBR_MST, (u32)(gwin1bufp +screen->x_res * screen->y_res));
         LcdMskReg(inf, SYS_CONFIG, m_W1_ENABLE|m_W0_ENABLE,v_W0_ENABLE(1)| v_W1_ENABLE(0));  
         testflag = 1;
     }
     else if(enable==2)
     {
         //rest lcdc clk
         rockchip_scu_reset_unit( 1 );
         memcpy(inf->preg, &inf->regbak, 47*4);  //resume reg
         
     }
     else
     {
         LcdMskReg(inf, SYS_CONFIG, m_W1_ENABLE|m_W0_ENABLE, v_W1_ENABLE(1)|v_W0_ENABLE(0)); 
         testflag = 0;
     }
     
     LcdWrReg(inf, REG_CFG_DONE, 0x01);
     
}
#endif 

drivers\video\rk2818_fb.h
/* 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
#define FB1_IOCTL_SET_ROTATE            0x5004
#define FB1_IOCTL_SCALE                 0x5005
#define FB1_IOCTL_MOV_POS               0x5006
#define FB1_IOCTL_FRAME_CTRL            0x5007
#define FB1_IOCTL_VIR_ADDR_ST           0x5008
#define FB1_IOCTL_SET_CTRL_ADDR         0x5009

/********************************************************************
**                          Структура определения                                *
********************************************************************/
/* 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;

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

extern void __init rk2818_add_device_lcdc(void);
extern int mcu_ioctl(unsigned int cmd, unsigned long arg);

#endif 

drivers\rk28_dsp.h
/*
 * rockchip_dsp.h  --  Dsp for rockchip
 *
 * Driver for rockchip dsp
 *  Copyright (C) 2009 lhh lhh@rock-chips.com
 *
 *  This program is free software; you can redistribute  it and/or modify it
 *  under  the terms of  the GNU General  Public License as published by the
 *  Free Software Foundation;  either version 2 of the  License, or (at your
 *  option) any later version.
 *
 *
 */

#ifndef __PLAT_ROCKCHIP_DSP_DSP_H
#define __PLAT_ROCKCHIP_DSP_DSP_H


#define PIU_CMD0_OFFSET         (0x30)
#define PIU_REPLY0_OFFSET       (0x3c)
#define PIU_STATUS_OFFSET       (0x4c)
#define PIU_IMASK_OFFSET        (0x48)
#define PIU_STATUS_R0WRS        3


#define CODEC_OUTPUT_PIU_CHANNEL        0
#define CODEC_MSG_PIU_CHANNEL           1
#define CODEC_MSG_PIU_NEXT_CHANNEL      2
#define CODEC_MSG_ICU_CHANNEL           3


#define DSP_IOCTL_RES_REQUEST           (0x00800000)
#define DSP_IOCTL_RES_RELEASE           (0x00800001)
#define DSP_IOCTL_SEND_MSG              (0x00800002)
#define DSP_IOCTL_RECV_MSG              (0x00800003)
#define DSP_IOCTL_SET_FREQ              (0x00800004)
#define DSP_IOCTL_GET_TABLE_PHY         (0x00800005)
#define DSP_IOCTL_SET_CODEC							(0x00800006)

struct rk28dsp_req {
	int reqno;
	char fwname[20];
	int freq;
};

struct rk28dsp_msg {
	int channel;
	uint32 cmd;
	int rcv_timeout;    // 0:no block   -1:block   >0:block with timeout
};

extern void rockchip_add_device_dsp(void);

#endif /* __PLAT_ROCKCHIP_DSP_DSP_H *//* insmod /system/lib/modules/rk28dsp.ko */

Сайт создан в системе uCoz