/* 2009-08-20: File added and changed by Sony Corporation */
/*
 * File Name       : /drivers/video/mp200/mp200_fb.c
 * Function        : FraemBuffer Driver corresponding to V4L2
 * Release Version :
 * Release Date    : 2009.03.27
 *
 * Copyright (C) NEC Electronics Corporation 2006-2009
 *
 *
 *  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 Free Softwere Foundation; either version 2
 *  of License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 *  without even the implied warrnty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *  See the GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along with this program;
 *  If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 *  MA 02111-1307, USA.
 *
 */

/*
 *
 *  framebuffer driver for D77601 -- based on vfb.c
 *
 */

/*
 *  linux/drivers/video/vfb.c -- Virtual frame buffer device
 *
 *      Copyright (C) 2002 James Simmons
 *
 *	Copyright (C) 1997 Geert Uytterhoeven
 *
 *  This file is subject to the terms and conditions of the GNU General Public
 *  License. See the file COPYING in the main directory of this archive for
 *  more details.
 */


/********************************************************
 *  Include Files                                       *
 *******************************************************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/timer.h>
#include <linux/sched.h>

#include <linux/platform_device.h>
#if defined(CONFIG_PM) || defined(CONFIG_DPM)
#include <asm/arch/pm.h>
#endif /* CONFIG_PM || CONFIG_DPM */

#include <asm/uaccess.h>
#include <asm/arch/hardware.h>
#include <asm/arch/irqs.h>
#include <asm/arch/em1_mem.h>
#include <asm/arch/fbcommon.h>

#ifdef CONFIG_FRAMEBUFFER_CONSOLE
#include "../console/fbcon.h"
#endif

#include "mp200_common.h"
#include "mp200_imc.h"
#include "mp200_lcd.h"
#include "mp200_lcdhw.h"
#include "nts/mp200_nts.h" 

#ifdef CONFIG_MACH_PGPF
#include "imc.h"
#include "lcdc.h"
#include <asm/arch/pgpf/lcdhw.h>
#include <asm/arch/pgpf/fb.h>
#endif /* CONFIG_MACH_PGPF */
#ifdef CONFIG_PGPF_BACKLIGHT
#include <linux/backlight.h>
#endif /* CONFIG_PGPF_BACKLIGHT */

/********************************************************
 *  Definitions                                         *
 *******************************************************/
#define _DEBUG_FB 0x00 /* 00008421(bit) */
                       /* 0x01: debug function in
                        * 0x02: debug function out
                        * 0x04: debug buffer
                        * 0x08: debug frame buffer status
                        * 0x10: debug update timer
						* 0x80: debug navu ioctl
						* 0x40: debug navu ioctl (verbose)
                        */

#define TIMEOUT_MSLEEP	0


/********************************************************
 *  Definitions                                         *
 *******************************************************/
#define DEV_NAME "mp200_fb"


/********************************************************
 *  Macros                                              *
 *******************************************************/
#define printk_err(fmt, arg...) \
	do{                     \
		printk(KERN_ERR DEV_NAME ": %s: " fmt, __func__, ## arg); \
	}while(0)

#define printk_wrn(fmt, arg...) \
	do{                     \
		printk(KERN_WARNING DEV_NAME ": %s: " fmt, __func__, ## arg); \
	}while(0)

#define printk_info(fmt, arg...) \
	do{                      \
		printk(KERN_INFO DEV_NAME ": " fmt, ## arg); \
	}while(0)

#if _DEBUG_FB
#define printk_dbg(level, fmt, arg...) \
	do{                            \
		if(level > 0) printk(KERN_DEBUG DEV_NAME ": %s: " fmt, __func__, ## arg); \
	}while(0)
#else
#define printk_dbg(level, fmt, arg...) \
	;
#endif


/********************************************************
 *  Definitions                                         *
 *******************************************************/
/* init function */
#define FB_INIT_ERROR__SMEM_NOT_RESERVE		-1
#define FB_INIT_ERROR__SMEM_NOT_REMAP		-2
#define FB_INIT_ERROR__FB_NOT_ALLOC		-3
#define FB_INIT_ERROR__FB_CMAP_NOT_ALLOC	-4
#define FB_INIT_ERROR__FB_NOT_REGIST		-5
#define FB_INIT_ERROR__LCD_NOT_INITIALIZE	-6

/* frame buffer page */
#define FB_NO_A				0
#define FB_NO_B				1

/* frame buffer status */
#define IS_NODATA			0
#define NOW_WRITING_TO_FB		1
#define ALREADY_DISPLAY			2
#define ENABLE_WRITE			3

/* timer */
#define TIMER_OFF			0
#define TIMER_ON			1
#define TIMEOUT_TIME			60 /* (ms) */
#define FB_TIMER_STOP			0
#define FB_TIMER_START			1

/* CHK_SCRN timer */
#define RECHK_TIME			10  /* (ms) */

/* timer default setting */
#define DEFALT_UPDATE_TIMER_LCD		TIMER_OFF
#ifdef CONFIG_FB_MP200_NTS
#define DEFALT_UPDATE_TIMER_NTS		TIMER_ON
#endif /* CONFIG_FB_MP200_NTS */

/* mmap */
#define MP200_FB_MMAP_MAX_SIZE	FB_FRAME_BUFFER_SIZE

#ifdef CONFIG_MACH_PGPF
/* Layer1 is enable on startup */
#define SHOW_OVERLAY_ON_STARTUP
#endif /* CONFIG_MACH_PGPF */
#ifdef CONFIG_PGPF_FB_PND_EXT
/* --- NAVU Option --- */
/* the layer on startup is set to Linux Console (Layer1 Buf2) */
#define START_WITH_LINUX_CONSOLE
/* initialize FB on startup (experimental) */
/* #define SHOW_EARLY */
#define AUTO_SCROLL_QUEUE_NAME "mp200_auto_scroll"
#endif /* CONFIG_PGPF_FB_PND_EXT */

/* Generic FB (Linux Console) transparency (0x00-0xff) */
#define GENERIC_FB_TRANSPARENCY 0xFF

/* Number of FB devices */
#ifdef CONFIG_FB_MP200_NTS
#define EM1_FB_DEVICES			2
#else	/* CONFIG_FB_MP200_NTS */
#define EM1_FB_DEVICES			1
#endif	/* CONFIG_FB_MP200_NTS */


#if 0
void ............Structure................(){}
#endif
/********************************************************
 *  Structure                                           *
 *******************************************************/
#ifdef CONFIG_PGPF_FB_PND_EXT
typedef struct _Coordinate {
	int x;
	int y;
} Coordinate;

typedef struct _scroll_info {
	Coordinate target;
	Coordinate speed;
	unsigned int flip;
	unsigned int status;
} scroll_info; /* request info for flip and/or scroll */

typedef struct _frame_setting {
    unsigned int  Status;
    unsigned int  Flip;
    int           DispX;
    int           DispY;
    unsigned int  DispWidth;
    unsigned int  DispHeight;
    unsigned int  FrameX;
    unsigned int  FrameY;
    unsigned int  FrameWidth;
    unsigned int  FrameHeight;
} frame_info;
#endif /* CONFIG_PGPF_FB_PND_EXT */

#ifdef CONFIG_MACH_PGPF
typedef struct _yuvaddr {
	uint32_t yrgbaddr;
	uint32_t uvaddr;
	uint32_t vaddr;
} yuv_addr;
#endif /* CONFIG_MACH_PGPF */

/* image infomation from 2D API */
typedef struct fb_other_image_info{
	int  iMaskColFlg;
	int  iMaskCol;
	int  iAlpha;
	int  iInvFlg;
	int  iPage;
	int  iUpDate;
} FB_OTHER_IMAGE_INFO;


/* image infomation from 2D API */
typedef struct _mp200_fb_par {
	struct fb_info          *fb_inf;
	atomic_t                 use_count;
	struct semaphore         sem_fb_image_info;		/* semafore for fb_image_info   */
	struct semaphore         sem_fb_other_info_A;		/* semafore for fb_other_info_A */
	struct semaphore         sem_fb_other_info_B;		/* semafore for fb_other_info_B */
	struct semaphore         sem_tvmode;			/* semafore for tvmode          */
	spinlock_t               fb_lock;			/* spin lock fb timer flag      */
#if (TIMEOUT_MSLEEP==0)
	wait_queue_head_t        wait_fb_chk_scrn;
#endif
	struct workqueue_struct *mp200_fb_workqueue;
	struct work_struct       wk_timeout_update_bottom_half;
#ifdef CONFIG_PGPF_FB_PND_EXT
	struct workqueue_struct *auto_scroll_workqueue;
	struct work_struct       wk_auto_scroll;
#endif /* CONFIG_PGPF_FB_PND_EXT */
	u32                      pseudo_palette[256];
	int                      devflag;			/* 0 : /dev/fb0   1 : /dev/fb1  */
} mp200_fb_par;


/* screen infomation default data */
static struct fb_var_screeninfo mp200_fb_default = 
{
	.xres           = FRONT_WIDTH,
	.yres           = FRONT_HEIGHT,
#if defined(CONFIG_PGPF_FB_PND_EXT)
	.xres_virtual   = LCD_CONSOLE_MAX_XRES,
	.yres_virtual   = LCD_CONSOLE_MAX_YRES,
#elif defined(CONFIG_PGPF_FB_UX_EXT)
	.xres_virtual   = FRONT_WIDTH_V,
	.yres_virtual   = FRONT_HEIGHT_V * FB_BUF_NUM,
#else /* CONFIG_PGPF_FB_PND_EXT */
	.xres_virtual   = FRONT_WIDTH_V,
	.yres_virtual   = FRONT_HEIGHT_V,
#endif /* CONFIG_PGPF_FB_PND_EXT */
	.xoffset        = 0,
	.yoffset        = 0,
	.grayscale      = 0,
	.bits_per_pixel = 16,
	.red            = {11, 5, 0},
	.green          = {5, 6, 0},
	.blue           = {0, 5, 0},
	.transp         = {0, 0, 0},
	.activate       = 0,
	.height         = -1,
	.width          = -1,
	.pixclock       = 0,
	.left_margin    = 0,
	.right_margin   = 0,
	.upper_margin   = 0,
	.lower_margin   = 0,
	.hsync_len      = 24,
	.vsync_len      = 4,
	.sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
	.vmode          = FB_VMODE_NONINTERLACED,
};

#ifdef CONFIG_FB_MP200_NTS
/* screen  tv infomation default data */
static struct fb_var_screeninfo mp200_fb_tv_default = 
{
	.xres           = NTS_WIDTH,
	.yres           = NTS_HEIGHT,
	.xres_virtual   = NTS_WIDTH_V,
	.yres_virtual   = NTS_HEIGHT_V,
	.xoffset        = 0,
	.yoffset        = 0,
	.grayscale      = 0,
	.bits_per_pixel = 16,
	.red            = {11, 5, 0},
	.green          = {5, 6, 0},
	.blue           = {0, 5, 0},
	.transp         = {0, 0, 0},
	.activate       = 0,
	.height         = -1,
	.width          = -1,
	.pixclock       = 0,
	.left_margin    = 0,
	.right_margin   = 0,
	.upper_margin   = 0,
	.lower_margin   = 0,
	.hsync_len      = 24,
	.vsync_len      = 4,
	.sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
	.vmode          = FB_VMODE_NONINTERLACED,
};
#endif /* CONFIG_FB_MP200_NTS */


/* screen infomation fix data */
static struct fb_fix_screeninfo mp200_fb_fix __initdata = 
{
	.id        = "MP200 FB",
	.type      = FB_TYPE_PACKED_PIXELS,
	.visual    = FB_VISUAL_TRUECOLOR,
	.xpanstep  = 1,
	.ypanstep  = 1,
	.ywrapstep = 1,
	.accel     = FB_ACCEL_NONE,
};

typedef struct mp200_fb_struct{
	int                   is_first;
	/* image infomation to LCD */
	FB_IMAGE_INFO         fb_image_info; /* L1B */
#ifdef CONFIG_PGPF_FB_PND_EXT
	FB_IMAGE_INFO         bg_image_info; /* BG */
	FB_IMAGE_INFO         console_image_info; /* L1A */
#endif /* CONFIG_PGPF_FB_PND_EXT */
#ifdef CONFIG_PGPF_FB_LAYER2
	V4L2_IMAGE_INFO       l2_image_info; /* L2A */
#endif /* CONFIG_PGPF_FB_LAYER2 */

	/* frame buffer A */
	FB_OTHER_IMAGE_INFO   fb_other_info_A;
	/* frame buffer B */
	FB_OTHER_IMAGE_INFO   fb_other_info_B;

	/* Disp Buffer (2D) */
	ulong   DispBufA;
	ulong   DispBufB;
	ulong   DispBufLength;
	char   *DispBufBV;
	char   *DispBufAV;

#ifdef CONFIG_PGPF_FB_LAYER2
	ulong   L2BufA;
	ulong   L2BufB;
	ulong   L2BufLength;
	char   *L2BufBV;
	char   *L2BufAV;
#ifndef CONFIG_PGPF_FB_PND_EXT
	unsigned int L2Flip;
#endif /* !CONFIG_PGPF_FB_PND_EXT */
#endif /* CONFIG_PGPF_FB_LAYER2 */

#ifdef CONFIG_PGPF_FB_PND_EXT
	/* BaseFrame Buffer */
	ulong   BaseBufA;
	ulong   BaseBufB;
	ulong   BaseBufLength;
	char   *BaseBufBV;
	char   *BaseBufAV;
	
	/* Linux Console Buffer */
	ulong   ConsoleBuf;
	ulong   ConsoleBufLength;
	char   *ConsoleBufV;

	/* NAVU Frame Info */
	scroll_info BaseScroll;
	frame_info  BaseFrame;
	scroll_info OverlayScroll;
	frame_info  OverlayFrame;
#ifdef CONFIG_PGPF_FB_LAYER2
	scroll_info SubScroll;
	frame_info  SubFrame;
#endif /* CONFIG_PGPF_FB_LAYER2 */
#endif /* CONFIG_PGPF_FB_PND_EXT */

	/* Timer */
	struct timer_list     mp200_fb_timer;
	int                   iTimeoutTime;
	mp200_fb_par          *mp200_fb_dev;
	/* flags */
	int                   iFBStatus_A;
	int                   iFBStatus_B;
	int                   iNowDispPage;   /* now on display page */
	int                   iNextDispPage;  /* next display page   */
	int                   iMixModeFlg;
	int                   iUpdateTimerFlag;
	int                   iTimerStatusFlag;
	int                   iDpmSuspendFlag;
}MP200_FB_STRUCT;

typedef struct mp200_fb_drvdata{
	struct fb_info *info[2];
#ifdef CONFIG_PGPF_NAVU2_PM
	spinlock_t suspend_lock;
#endif /* CONFIG_PGPF_NAVU2_PM */
}MP200_FB_DRVDATA;


#if 0
void ............Variables................(){}
#endif
/********************************************************
 *  Variables                                           *
 *******************************************************/
static MP200_FB_STRUCT    fb_data[2];
static EM1_TV_MODE        tvmode;
static MP200_FB_DRVDATA   drvdata;
/* Smem */
static  ulong             Smem       = SMEM_START;
static  ulong             SmemLength = SMEM_LENGTH;
        char             *SmemV;
static  ulong             DispBufAllLength = MP200_FB_MMAP_MAX_SIZE;

#if defined(CONFIG_PGPF_FB_PND_EXT) || defined(CONFIG_PGPF_FB_UX_EXT)
static wait_queue_head_t mp200_vsync_wq;
static int vsync_flag;
#endif /* CONFIG_PGPF_FB_*_EXT */

/********************************************************
 *  Prototype declarations of function                  *
 *******************************************************/
/* public function */
        int            mp200_fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg);
        int            mp200_fb_mmap(struct fb_info *info, struct vm_area_struct *vma);
        void           mp200_fb_callback(int iWrittenFBNo, int iMixModeStatus, int fb_num);
        int   __init   mp200_fb_init_module(void);

#ifdef CONFIG_PGPF_BACKLIGHT
#ifdef CONFIG_PGPF_NAVU2
int                    mp200_fb_set_tpled(int mode);
#endif /* CONFIG_PGPF_NAVU2 */
int                    mp200_fb_set_brightness(int brightness);
int                    mp200_fb_get_brightness(void);
#endif /* CONFIG_PGPF_BACKLIGHT */

/* private function */
#ifdef CONFIG_PGPF_BACKLIGHT
#ifdef CONFIG_PGPF_NAVU2
static int             mp200_fb_ioc_set_tpled(struct fb_info *info, unsigned long arg);
#endif
static int             mp200_fb_ioc_set_brightness(struct fb_info *info, unsigned long arg);
static int             mp200_fb_ioc_get_brightness(struct fb_info *info, unsigned long arg);
#endif /* CONFIG_PGPF_BACKLIGHT */

#ifdef CONFIG_MACH_PGPF
#ifdef CONFIG_PGPF_FB_PND_EXT
/* navu ioctl */
static  int            mp200_fb_ioc_disp(struct fb_info *info, unsigned long arg);
static  int            mp200_fb_ioc_waitvsync(struct fb_info *info, unsigned long arg);
/* Base Frame */
static  int            mp200_fb_ioc_layer0(struct fb_info *info, unsigned long arg);
static  int            mp200_fb_ioc_setscroll0(struct fb_info *info, unsigned long arg);
static  int            mp200_fb_ioc_setscroll_flip0(struct fb_info *info, unsigned long arg);
static  int            mp200_fb_ioc_getscroll0(struct fb_info *info, unsigned long arg);
static  int            mp200_fb_ioc_selbuf0(struct fb_info *info, unsigned long arg);
static  int            mp200_fb_ioc_getframe0(struct fb_info *info, unsigned long arg);
static  int            mp200_fb_ioc_getbase0(struct fb_info *info, unsigned long arg);
/* Overlay */
static  int            mp200_fb_ioc_layer1(struct fb_info *info, unsigned long arg);
static  int            mp200_fb_ioc_selbuf1(struct fb_info *info, unsigned long arg);
static  int            mp200_fb_ioc_getdisp1(struct fb_info *info, unsigned long arg);
static  int            mp200_fb_ioc_getbase1(struct fb_info *info, unsigned long arg);
#ifdef CONFIG_PGPF_FB_LAYER2
/* Sub Frame */
static  int            mp200_fb_ioc_layer2(struct fb_info *info, unsigned long arg);
static  int            mp200_fb_ioc_setscroll2(struct fb_info *info, unsigned long arg);
static  int            mp200_fb_ioc_setscroll_flip2(struct fb_info *info, unsigned long arg);
static  int            mp200_fb_ioc_getscroll2(struct fb_info *info, unsigned long arg);
static  int            mp200_fb_ioc_selbuf2(struct fb_info *info, unsigned long arg);
static  int            mp200_fb_ioc_setdisp2(struct fb_info *info, unsigned long arg);
static  int            mp200_fb_ioc_getdisp2(struct fb_info *info, unsigned long arg);
static  int            mp200_fb_ioc_setformat2(struct fb_info *info, unsigned long arg);
static  int            mp200_fb_ioc_getformat2(struct fb_info *info, unsigned long arg);
static  int            mp200_fb_ioc_getbase2(struct fb_info *info, unsigned long arg);
static  int            mp200_fb_ioc_getaddroffset2(struct fb_info *info, unsigned long arg);
#endif /* CONFIG_PGPF_FB_LAYER2 */
/* Linux Console */
static  int            mp200_fb_ioc_settrans3(struct fb_info *info, unsigned long arg);
static  int            mp200_fb_ioc_getdisp3(struct fb_info *info, unsigned long arg);
static  int            mp200_fb_ioc_getbase3(struct fb_info *info, unsigned long arg);
#else /* CONFIG_PGPF_FB_PND_EXT */
static  int            mp200_fb_ioc_set_lcd_status(struct fb_info *info, unsigned long arg);
static  int            mp200_fb_ioc_wait_vsync(struct fb_info *info, unsigned long arg);
static  int            mp200_fb_ioc_gui_set_enabled(struct fb_info *info, unsigned long arg);
static  int            mp200_fb_ioc_gui_set_trans(struct fb_info *info, unsigned long arg);
#ifdef CONFIG_PGPF_FB_LAYER2
static  int            mp200_fb_ioc_photo_set_enabled(struct fb_info *info, unsigned long arg);
static  int            mp200_fb_ioc_photo_select_buf(struct fb_info *info, unsigned long arg);
static  int            mp200_fb_ioc_photo_set_frame(struct fb_info *info, unsigned long arg);
static  int            mp200_fb_ioc_photo_get_frame(struct fb_info *info, unsigned long arg);
static  int            mp200_fb_ioc_photo_set_format(struct fb_info *info, unsigned long arg);
static  int            mp200_fb_ioc_photo_get_format(struct fb_info *info, unsigned long arg);
static  int            mp200_fb_ioc_photo_get_base(struct fb_info *info, unsigned long arg);
static  int            mp200_fb_ioc_photo_get_offset(struct fb_info *info, unsigned long arg);
#endif /* CONFIG_PGPF_FB_LAYER2 */
#endif /* CONFIG_PGPF_FB_PND_EXT */
#endif /* CONFIG_MACH_PGPF */

#ifndef CONFIG_PGPF_FB_UX_EXT
static  int            mp200_fb_ioc_chk_scrn(struct fb_info *info, unsigned long arg);
static  int            mp200_fb_ioc_get_modes(struct fb_info *info, unsigned long arg);
static  int            mp200_fb_ioc_set_modes(struct fb_info *info, unsigned int cmd, unsigned long arg);
static  int            mp200_fb_ioc_update_scrn(struct fb_info *info, unsigned int cmd, unsigned long arg);
static  int            mp200_fb_ioc_update_timer(struct fb_info *info, unsigned long arg);
#endif /* !CONFIG_PGPF_FB_UX_EXT */
#ifdef CONFIG_FB_MP200_NTS
static  int            mp200_fb_ioc_set_output(struct fb_info *info, unsigned long arg);
static  int            mp200_fb_ioc_get_output(struct fb_info *info, unsigned long arg);
#endif /* CONFIG_FB_MP200_NTS */

#ifndef CONFIG_PGPF_FB_UX_EXT
static  int            set_image_info_to_2DAPI(int iFBNo, scrn_modes *fb_scrn_modes, struct fb_info *info);
static  int            chk_fb_status(int iFBStatus);
static  int            chk_input_modes(scrn_modes fb_scrn_modes);
static  int            set_image_info_from_2DAPI(int iFBNo, scrn_modes *fb_scrn_modes, struct fb_info *info);
static  int            set_image_info_to_LCD(int iFBNo, struct fb_info *info);
static  int            chk_input_update_timer(update_timer *fb_timer);
#endif /* !CONFIG_PGPF_FB_UX_EXT */
#ifdef CONFIG_FB_MP200_NTS
static void            set_tv_size( EM1_TV_MODE mode, mp200_fb_par *par );
static void            set_tv_var(EM1_TV_MODE mode, mp200_fb_par *par);
#endif /* CONFIG_FB_MP200_NTS */
static  int            mp200_fb_open(struct fb_info *info, int user);
static  int            mp200_fb_release(struct fb_info *info, int user);
static  u_long         get_line_length(int xres_virtual, int bpp);
static  int            mp200_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info);
static  int            mp200_fb_set_par(struct fb_info *info);
static  int            mp200_fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info *info);
static  int            mp200_fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info);
static  int            mp200_fb_remove(struct platform_device *device);
static  int    __init  mp200_fb_probe(struct platform_device *device);
static  void   __init  mp200_fb_probe_error(int iErrorMode, struct fb_info *info_0, struct fb_info *info_1, int fb_num);
static  void           set_buffer_address(int fb_num);
static  void           set_info(struct fb_info *info, mp200_fb_par **par,int fb_num);
static  void           set_flag_init(int fb_num);
static  void           set_val_init(struct fb_info *info, int fb_num);
static  void           timer_init(struct fb_info *info);
static  void           timeout_update( unsigned long data );
#if defined(CONFIG_PM) || defined(CONFIG_DPM)
#ifdef CONFIG_PGPF_NAVU2_PM
int                    mp200_fb_suspend(struct platform_device *dev, pm_message_t state);
#else /* CONFIG_PGPF_NAVU2_PM */
static  int            mp200_fb_suspend(struct platform_device *dev, pm_message_t state);
#endif /* CONFIG_PGPF_NAVU2_PM */
static  int            mp200_fb_suspend_sub(struct platform_device *dev, pm_message_t state, int fb_num);
#ifdef CONFIG_PGPF_NAVU2_PM
int                    mp200_fb_resume(struct platform_device *dev);
#else /* CONFIG_PGPF_NAVU2_PM */
static  int            mp200_fb_resume(struct platform_device *dev);
#endif /* CONFIG_PGPF_NAVU2_PM */
static  int            mp200_fb_resume_sub(struct platform_device *dev, int fb_num);
#endif /* CONFIG_PM || CONFIG_DPM */

/* workqueue function */
static void            timeout_update_bottom_half_do(struct work_struct *num);

#ifdef CONFIG_MACH_PGPF
static inline int mp200_is_lcd_enable(void)
{
	return readl(IO_ADDRESS(LCDC_BASE) + LCD_STATUS);
}
#endif /* CONFIG_MACH_PGPF */

/********************************************************
 *  Function Structure                                  *
 *******************************************************/
/* fb ops */
static struct fb_ops mp200_fb_ops = {
	.owner          = THIS_MODULE,
	.fb_open        = mp200_fb_open,
	.fb_release     = mp200_fb_release,
	.fb_check_var   = mp200_fb_check_var,
	.fb_set_par     = mp200_fb_set_par,
	.fb_setcolreg   = mp200_fb_setcolreg,
	.fb_pan_display = mp200_fb_pan_display,
	.fb_fillrect    = cfb_fillrect,  /* fb common function */
	.fb_copyarea    = cfb_copyarea,  /* fb common function */
	.fb_imageblit   = cfb_imageblit, /* fb common function */
#ifdef CONFIG_FRAMEBUFFER_CONSOLE
	.fb_cursor      = soft_cursor,   /* fb common function */
#endif /* CONFIG_FRAMEBUFFER_CONSOLE */
	.fb_ioctl       = mp200_fb_ioctl,
	.fb_mmap        = mp200_fb_mmap,
};

/* platform driver */
static struct platform_driver mp200_fb_driver = {
	.probe       = mp200_fb_probe,
	.remove      = mp200_fb_remove,

#if defined(CONFIG_PM) || defined(CONFIG_DPM)
	.suspend     = mp200_fb_suspend,
#ifndef CONFIG_PGPF_NAVU2_PM
	.resume      = mp200_fb_resume,
#endif /* !CONFIG_PGPF_NAVU2_PM */
#endif /* CONFIG_PM || CONFIG_DPM */

	.driver.name = DEV_NAME,
	.driver.bus  = &platform_bus_type,
};


#if 0
void ............ioctl................(){}
#endif
/********************************************************
 *  Function Definitions                                *
 *******************************************************/
#ifdef CONFIG_MACH_PGPF
static inline int mp200_fb_set_image(FB_IMAGE_INFO *fb_image_info, FB_IMAGE_INFO *bg_image_info, V4L2_IMAGE_INFO *l2_image_info, FB_IMAGE_INFO *console_image_info, int fb_num)
{
	if (fb_data[fb_num].iUpdateTimerFlag == TIMER_OFF) {
		fb_data[fb_num].fb_image_info.update_flag = FB_ABSOLUTERY_UPDATE;
		if(mp200_lcd_set_fb_image_ex2(fb_image_info, bg_image_info, l2_image_info, console_image_info)){
			return -EBUSY;
		}
	}
	return 0;
}


static inline int mp200_fb_set_lcd_status(struct fb_info *info, unsigned long arg)
{
	int ret = 0;
	mp200_fb_par *par = (mp200_fb_par *)info->par;
	unsigned int mode;
	
	if (get_user(mode, (unsigned int *)arg)) {
		return -EFAULT;
	}
	if (mode == 0 || mode == 1) {
		/* mode 
		 * 0: suspend 
		 * 1: resume 
		 */ 
		if (down_interruptible(&par->sem_fb_image_info)) {
			return -EBUSY;
		}
		if (mode == 0) {
			mp200_fb_suspend(NULL, PMSG_SUSPEND);
		} else {
			mp200_fb_resume(NULL);
			ret = mp200_fb_set_image(&fb_data[par->devflag].fb_image_info, NULL, NULL, NULL, par->devflag);
			if (ret) {
				up(&par->sem_fb_image_info);
				return ret;
			}
		}
		up(&par->sem_fb_image_info);
	}
	ret = mode;

	return ret;
}

static inline int mp200_fb_wait_vsync(struct fb_info *info, unsigned long arg)
{
	int ret = 0;
	mp200_fb_par *par = (mp200_fb_par *)info->par;
	
	vsync_flag = 0;
	if (down_interruptible(&par->sem_fb_image_info)) {
		return -EBUSY;
	}
	ret = mp200_fb_set_image(&fb_data[par->devflag].fb_image_info, NULL, NULL, NULL, par->devflag);
	if (ret) {
		up(&par->sem_fb_image_info);
		return ret;
	}
	wait_event_interruptible(mp200_vsync_wq, (vsync_flag != 0));
	up(&par->sem_fb_image_info);

	return ret;
}

#ifdef CONFIG_PGPF_FB_LAYER2
static void mp200_fb_l2_set_address(int flip, int fb_num)
{
	if (flip == 0) {
		fb_data[fb_num].l2_image_info.image_data.yrgbaddr = fb_data[fb_num].L2BufA;
	} else {
		fb_data[fb_num].l2_image_info.image_data.yrgbaddr = fb_data[fb_num].L2BufB;
	}

	switch (fb_data[fb_num].l2_image_info.yuvfmt) {
	case IMC_Lx_FORMAT_RGB666:
		fb_data[fb_num].l2_image_info.image_data.uvaddr = fb_data[fb_num].l2_image_info.image_data.vaddr = 0;
		fb_data[fb_num].l2_image_info.image_data.size = fb_data[fb_num].l2_image_info.image_data.hsize * 18 / 8;
		break;
	case IMC_Lx_FORMAT_RGB565:
	case IMC_Lx_FORMAT_YUV422Px:
		fb_data[fb_num].l2_image_info.image_data.uvaddr = fb_data[fb_num].l2_image_info.image_data.vaddr = 0;
		fb_data[fb_num].l2_image_info.image_data.size = fb_data[fb_num].l2_image_info.image_data.hsize * 16 / 8;
		break;
	case IMC_Lx_FORMAT_YUV422Pl2:
	case IMC_Lx_FORMAT_YUV420Pl2:
		fb_data[fb_num].l2_image_info.image_data.uvaddr
			= fb_data[fb_num].l2_image_info.image_data.yrgbaddr
			+ fb_data[fb_num].l2_image_info.image_data.hsize * fb_data[fb_num].l2_image_info.image_data.vsize;
		fb_data[fb_num].l2_image_info.image_data.vaddr = 0;
		fb_data[fb_num].l2_image_info.image_data.size = fb_data[fb_num].l2_image_info.image_data.hsize * 16 / 8 / 2;
		break;
	case IMC_Lx_FORMAT_YUV422Pl:
		fb_data[fb_num].l2_image_info.image_data.uvaddr
			= fb_data[fb_num].l2_image_info.image_data.yrgbaddr
			+ fb_data[fb_num].l2_image_info.image_data.hsize * fb_data[fb_num].l2_image_info.image_data.vsize;
		fb_data[fb_num].l2_image_info.image_data.vaddr
			= fb_data[fb_num].l2_image_info.image_data.uvaddr
			+ fb_data[fb_num].l2_image_info.image_data.hsize * fb_data[fb_num].l2_image_info.image_data.vsize / 2;
		fb_data[fb_num].l2_image_info.image_data.size = fb_data[fb_num].l2_image_info.image_data.hsize * 16 / 8 / 2;
		break;
	case IMC_Lx_FORMAT_YUV420Pl:
		fb_data[fb_num].l2_image_info.image_data.uvaddr
			= fb_data[fb_num].l2_image_info.image_data.yrgbaddr
			+ fb_data[fb_num].l2_image_info.image_data.hsize * fb_data[fb_num].l2_image_info.image_data.vsize;
		fb_data[fb_num].l2_image_info.image_data.vaddr
			= fb_data[fb_num].l2_image_info.image_data.uvaddr
			+ fb_data[fb_num].l2_image_info.image_data.hsize * fb_data[fb_num].l2_image_info.image_data.vsize / 4;
		fb_data[fb_num].l2_image_info.image_data.size = fb_data[fb_num].l2_image_info.image_data.hsize * 16 / 8 / 2;
		break;
	default:
		fb_data[fb_num].l2_image_info.image_data.uvaddr = fb_data[fb_num].l2_image_info.image_data.vaddr = 0;
		break;
	}
}

static inline int mp200_fb_l2_get_address_base(struct fb_info *info, unsigned long arg)
{
	int ret = 0;
	unsigned int page;

	if (get_user(page, (unsigned int *)arg)) {
		return -EFAULT;
	}
	switch (page) {
	case 0:
		ret = SUB_A_OFFSET;
		break;
	case 1:
		ret = SUB_B_OFFSET;
		break;
	default:
		printk_err("invalid argument!\n");
		ret = -EINVAL;
		break;
	}
	
	return ret;
}

static inline int mp200_fb_l2_get_address_offset(struct fb_info *info, yuv_addr* offset)
{
	int ret = 0;
	mp200_fb_par *par = (mp200_fb_par *)info->par;

	if (offset == NULL) {
		return -EFAULT;
	}
	offset->yrgbaddr = 0;
	switch (fb_data[par->devflag].l2_image_info.yuvfmt) {
	case IMC_Lx_FORMAT_RGB666:
	case IMC_Lx_FORMAT_RGB565:
	case IMC_Lx_FORMAT_YUV422Px:
		offset->uvaddr = 0;
		offset->vaddr = 0;
		break;
	case IMC_Lx_FORMAT_YUV422Pl2:
	case IMC_Lx_FORMAT_YUV420Pl2:
		offset->uvaddr = fb_data[par->devflag].l2_image_info.image_data.uvaddr - fb_data[par->devflag].l2_image_info.image_data.yrgbaddr;
		offset->vaddr = 0;
		break;
	case IMC_Lx_FORMAT_YUV422Pl:
	case IMC_Lx_FORMAT_YUV420Pl:
		offset->uvaddr = fb_data[par->devflag].l2_image_info.image_data.uvaddr - fb_data[par->devflag].l2_image_info.image_data.yrgbaddr;
		offset->vaddr = fb_data[par->devflag].l2_image_info.image_data.vaddr - fb_data[par->devflag].l2_image_info.image_data.yrgbaddr;	
		break;
	default:
		printk_err("not supported format!\n");
		return -EINVAL;
	}

	return ret;
}
#endif /* CONFIG_PGPF_FB_LAYER2 */


#endif /* CONFIG_MACH_PGPF */

#ifdef CONFIG_PGPF_FB_PND_EXT
static int mp200_check_scroll(frame_info* frame, SONY_NAVU_SETSCROLL_FLIP* scroll_flip)
{
	int ret = 0;

	if ((scroll_flip->FrameX != SONY_NAVU_FAR_LIMIT && scroll_flip->FrameX > frame->FrameWidth) ||
		(scroll_flip->FrameY != SONY_NAVU_FAR_LIMIT && scroll_flip->FrameY > frame->FrameHeight) ||
		(scroll_flip->SpeedFrameX != SONY_NAVU_SPEED_WARP && (scroll_flip->SpeedFrameX > 1000 || scroll_flip->SpeedFrameX < -1000)) || 
		(scroll_flip->SpeedFrameY != SONY_NAVU_SPEED_WARP && (scroll_flip->SpeedFrameY > 1000 || scroll_flip->SpeedFrameY < -1000)) ||
		(scroll_flip->StartX != SONY_NAVU_FAR_LIMIT && scroll_flip->StartX > frame->FrameWidth - frame->DispWidth) || 
		(scroll_flip->StartY != SONY_NAVU_FAR_LIMIT && scroll_flip->StartY > frame->FrameHeight - frame->DispHeight) ||
		scroll_flip->Flip > 1) {
			ret = -EINVAL;
	}

	return ret;
}

static int mp200_check_frame(frame_info* frame, SONY_NAVU_DISPSETTING* disp)
{
	if ((disp->DispWidth > frame->FrameWidth) ||
		(disp->DispHeight > frame->FrameHeight) ||
		(disp->FrameX > (frame->FrameWidth - disp->DispWidth))|| 
		(disp->FrameY > (frame->FrameHeight - disp->DispHeight)) || 
		(disp->DispWidth > LCD_WIDTH) ||
		(disp->DispHeight > LCD_HEIGHT) ||
		(disp->DispX > (LCD_WIDTH - disp->DispWidth)) || 
		(disp->DispY > (LCD_HEIGHT - disp->DispHeight))) {
		return -EINVAL;
	}
	return 0;
}

static int mp200_auto_scroll_is_active(int fb_num)
{
#ifdef CONFIG_PGPF_FB_LAYER2
	return (fb_data[fb_num].BaseScroll.status & SONY_NAVU_SCROLL_AUTO) || (fb_data[fb_num].SubScroll.status & SONY_NAVU_SCROLL_AUTO);
#else
	return (fb_data[fb_num].BaseScroll.status & SONY_NAVU_SCROLL_AUTO);
#endif /* CONFIG_PGPF_FB_LAYER2 */

}

static int mp200_auto_scroll_check(frame_info* frame, scroll_info* scroll)
{
	if (((scroll->speed.x != 0) || (scroll->speed.y != 0)) || (scroll->flip != frame->Flip)) {
		return 1;
	}

	return 0;
}

static int mp200_auto_scroll_prep(struct fb_info* info, int fb_num, frame_info* frame, scroll_info* scroll)
{
	Coordinate next;
    int flag;

	scroll->status |= SONY_NAVU_SCROLL_AUTO | SONY_NAVU_SCROLL_ACTIVE;
	
	if ((scroll->speed.x == SONY_NAVU_SPEED_WARP) && (scroll->speed.y == SONY_NAVU_SPEED_WARP)) {
		next.x = scroll->target.x;
		next.y = scroll->target.y;
	}
	else {
		next.x = (frame->FrameX + scroll->speed.x);
		next.y = (frame->FrameY + scroll->speed.y);
	}
	
	flag = 0;
	
	/* Decide next point */
	if ((scroll->target.x != SONY_NAVU_FAR_LIMIT) || (scroll->target.y != SONY_NAVU_FAR_LIMIT)) {
		if (frame->FrameX < scroll->target.x) {
			if (next.x > scroll->target.x) {
				next.x = scroll->target.x;
			}
		}
		else {
			if (next.x < scroll->target.x) {
				next.x = scroll->target.x;
			}
		}
		if (frame->FrameX == scroll->target.x) {
			next.x = scroll->target.x;
		}
		
		if (frame->FrameY < scroll->target.y) {
			if (next.y > scroll->target.y) {
				next.y = scroll->target.y;
			}
		}
		else {
			if (next.y < scroll->target.y) {
				next.y = scroll->target.y;
			}
		}
		if (frame->FrameY == scroll->target.y) {
			next.y = scroll->target.y;
		}
		
		if ((next.y == scroll->target.y) && (next.x == scroll->target.x)) {
			flag |= SONY_NAVU_SCROLL_GOAL;
		}
	}
	
	/* Examine out of bound */
	if (((next.x < 0) || ((frame->FrameWidth  - frame->DispWidth)  < next.x)) ||
		((next.y < 0) || ((frame->FrameHeight - frame->DispHeight) < next.y))) {
		flag |= SONY_NAVU_SCROLL_OB;
	}
	
	/* Stop if exceeds limit */
	if (flag & SONY_NAVU_SCROLL_OB) {
		next.x = frame->FrameX;
		next.y = frame->FrameY;
	}
	
	/* Update property */
	frame->FrameX = next.x;
	frame->FrameY = next.y;
	frame->Flip = scroll->flip;
	
	return flag;
}

static int mp200_auto_scroll_post(scroll_info* scroll, int flag)
{
	if (flag != 0) {
		scroll->speed.x = 0;
		scroll->speed.y = 0;
	}
	scroll->status &= ~SONY_NAVU_SCROLL_RESULT_MASK;
	scroll->status |= flag;
	return 0;
}

static int mp200_auto_scroll(struct fb_info *info, int fb_num)
{
	int ret = 0;

	int bg_modify = 0;
	int sub_modify = 0;

	int bg_flag = 0;
#ifdef CONFIG_PGPF_FB_LAYER2
	int sub_flag = 0;
#endif /* CONFIG_PGPF_FB_LAYER2 */

#ifdef CONFIG_PGPF_FB_LAYER2
	printk_dbg((_DEBUG_FB & 0x80), "pre: Base = 0x%08x, Sub = 0x%08x\n", 
			   fb_data[fb_num].BaseScroll.status, fb_data[fb_num].SubScroll.status);
#endif /* CONFIG_PGPF_FB_LAYER2 */

	bg_modify = mp200_auto_scroll_check(&fb_data[fb_num].BaseFrame, &fb_data[fb_num].BaseScroll);
	if (bg_modify) {
		bg_flag = mp200_auto_scroll_prep(info, fb_num, &fb_data[fb_num].BaseFrame, &fb_data[fb_num].BaseScroll);
		if (fb_data[fb_num].BaseFrame.Flip == 0) {
			fb_data[fb_num].bg_image_info.image_data.yrgbaddr = fb_data[fb_num].BaseBufA;
		} else {
			fb_data[fb_num].bg_image_info.image_data.yrgbaddr = fb_data[fb_num].BaseBufB;
		}
		fb_data[fb_num].bg_image_info.image_data.x = fb_data[fb_num].BaseFrame.FrameX;
		fb_data[fb_num].bg_image_info.image_data.y = fb_data[fb_num].BaseFrame.FrameY;
	} else {
		fb_data[fb_num].BaseScroll.status &= SONY_NAVU_SCROLL_RESULT_MASK;
	}

#ifdef CONFIG_PGPF_FB_LAYER2
	sub_modify = mp200_auto_scroll_check(&fb_data[fb_num].SubFrame, &fb_data[fb_num].SubScroll);
	if (sub_modify) {
		sub_flag = mp200_auto_scroll_prep(info, fb_num, &fb_data[fb_num].SubFrame, &fb_data[fb_num].SubScroll);
		mp200_fb_l2_set_address(fb_data[fb_num].SubFrame.Flip, fb_num);
		fb_data[fb_num].l2_image_info.image_data.x = fb_data[fb_num].SubFrame.FrameX;
		fb_data[fb_num].l2_image_info.image_data.y = fb_data[fb_num].SubFrame.FrameY;
	} else {
		fb_data[fb_num].SubScroll.status &= SONY_NAVU_SCROLL_RESULT_MASK;
	}
#endif /* CONFIG_PGPF_FB_LAYER2 */
	
	if (bg_modify || sub_modify) {
#ifdef CONFIG_PGPF_FB_LAYER2
		ret = mp200_fb_set_image(&fb_data[fb_num].fb_image_info, &fb_data[fb_num].bg_image_info, &fb_data[fb_num].l2_image_info, NULL, fb_num);
#else /* CONFIG_PGPF_FB_LAYER2 */
		ret = mp200_fb_set_image(&fb_data[fb_num].fb_image_info, &fb_data[fb_num].bg_image_info,NULL,  NULL, fb_num);
#endif /* CONFIG_PGPF_FB_LAYER2 */
	}

	if (ret == 0) {
		if (bg_modify) {
			mp200_auto_scroll_post(&fb_data[fb_num].BaseScroll, bg_flag);
		}
#ifdef CONFIG_PGPF_FB_LAYER2
		if (sub_modify) {
			mp200_auto_scroll_post(&fb_data[fb_num].SubScroll, sub_flag);
		}
		printk_dbg((_DEBUG_FB & 0x80), "post: Base = 0x%08x, Sub = 0x%08x\n", 
			   fb_data[fb_num].BaseScroll.status, fb_data[fb_num].SubScroll.status);
#endif /* CONFIG_PGPF_FB_LAYER2 */
	}

	return ret;
}

static void auto_scroll_do(struct work_struct *num)
{
	mp200_fb_par *par = container_of(num, mp200_fb_par, wk_auto_scroll);
	struct fb_info *info = par->fb_inf;
	if (down_trylock(&par->sem_fb_image_info)) {
		printk_dbg((_DEBUG_FB & 0x80), "down_trylock failed\n");
		return;
	}
	mp200_auto_scroll(info, par->devflag);
	up(&par->sem_fb_image_info);
}
#endif /* CONFIG_PGPF_FB_PND_EXT */

/******************************************************************************
* MODULE   : mp200_fb_ioctl
* FUNCTION : frame buffer driver ioctl
* RETURN   :  0      : success
*            -1      :
*            -EFAULT :
*            -EBUSY  :
*            -ENXIO  :
*            -ENOIOCTLCMD:
* NOTE     : none
* CREATE   : 2006.05.26 H.Nagashima
* UPDATE   : 2008.11.25 J.Manabe
******************************************************************************/
int mp200_fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
{
#ifdef CONFIG_MACH_PGPF
	mp200_fb_par *par = (mp200_fb_par *)info->par;
	if (fb_data[par->devflag].iDpmSuspendFlag
#ifdef CONFIG_MACH_PGPF
#ifdef CONFIG_PGPF_FB_PND_EXT
		&& cmd != SONY_NAVU_FBIO_DISP
#else /* CONFIG_PGPF_FB_PND_EXT */
		&& cmd != PGPF_FBIO_SET_LCD_STATUS
#endif /* CONFIG_PGPF_FB_PND_EXT */
#endif /* CONFIG_MACH_PGPF */
		) {
		printk_err("ioctl call on suspend!\n");
		return -EBUSY;
	}
#endif /* CONFIG_MACH_PGPF */

	switch (cmd)
	{
#ifdef CONFIG_MACH_PGPF
#ifdef CONFIG_PGPF_BACKLIGHT
#ifdef CONFIG_PGPF_NAVU2
	case SONY_NAVU_FBIO_TPLED:
		return mp200_fb_ioc_set_tpled(info, arg);
#endif /* CONFIG_PGPF_NAVU2 */
	case PGPF_FBIO_SET_BRIGHTNESS:
		return mp200_fb_ioc_set_brightness(info, arg);
	case PGPF_FBIO_GET_BRIGHTNESS:
		return mp200_fb_ioc_get_brightness(info, arg);
#endif /* CONFIG_PGPF_BACKLIGHT */

#ifdef CONFIG_PGPF_FB_PND_EXT
		/* navu ioctl */
	case SONY_NAVU_FBIO_DISP:
		return mp200_fb_ioc_disp(info, arg);
	case SONY_NAVU_FBIO_WAITVSYNC:
		return mp200_fb_ioc_waitvsync(info, arg);

		/* Base Frame */
	case SONY_NAVU_FBIO_LAYER0:
		return mp200_fb_ioc_layer0(info, arg);
	case SONY_NAVU_FBIO_SETSCROLL0:
		return mp200_fb_ioc_setscroll0(info, arg);
	case SONY_NAVU_FBIO_SETSCROLL_FLIP0:
		return mp200_fb_ioc_setscroll_flip0(info, arg);
	case SONY_NAVU_FBIO_GETSCROLL0:
		return mp200_fb_ioc_getscroll0(info, arg);
	case SONY_NAVU_FBIO_SELBUF0:
		return mp200_fb_ioc_selbuf0(info, arg);
	case SONY_NAVU_FBIO_GETFRAME0:
		return mp200_fb_ioc_getframe0(info, arg);
	case SONY_NAVU_FBIO_GETBASE0:
		return mp200_fb_ioc_getbase0(info, arg);

		/* Overlay */
	case SONY_NAVU_FBIO_LAYER1:
		return mp200_fb_ioc_layer1(info, arg);
	case SONY_NAVU_FBIO_SELBUF1:
		return mp200_fb_ioc_selbuf1(info, arg);
	case SONY_NAVU_FBIO_GETDISP1:
		return mp200_fb_ioc_getdisp1(info, arg);
	case SONY_NAVU_FBIO_GETBASE1:
		return mp200_fb_ioc_getbase1(info, arg);

#ifdef CONFIG_PGPF_FB_LAYER2
		/* Sub Frame*/
	case SONY_NAVU_FBIO_LAYER2:
		return mp200_fb_ioc_layer2(info, arg);
	case SONY_NAVU_FBIO_SETSCROLL2:
		return mp200_fb_ioc_setscroll2(info, arg);
	case SONY_NAVU_FBIO_SETSCROLL_FLIP2:
		return mp200_fb_ioc_setscroll_flip2(info, arg);
	case SONY_NAVU_FBIO_GETSCROLL2:
		return mp200_fb_ioc_getscroll2(info, arg);
	case SONY_NAVU_FBIO_SELBUF2:
		return mp200_fb_ioc_selbuf2(info, arg);
	case SONY_NAVU_FBIO_SETDISP2:
		return mp200_fb_ioc_setdisp2(info, arg);
	case SONY_NAVU_FBIO_GETDISP2:
		return mp200_fb_ioc_getdisp2(info, arg);
	case SONY_NAVU_FBIO_SETFORMAT2:
		return mp200_fb_ioc_setformat2(info, arg);
	case SONY_NAVU_FBIO_GETFORMAT2:
		return mp200_fb_ioc_getformat2(info, arg);
	case SONY_NAVU_FBIO_GETBASE2:
		return mp200_fb_ioc_getbase2(info, arg);
	case SONY_NAVU_FBIO_GETADDROFFSET2:
		return mp200_fb_ioc_getaddroffset2(info, arg);
#endif /* CONFIG_PGPF_FB_LAYER2 */

		/* Linux Console (just for test) */
	case SONY_NAVU_FBIO_SETTRANS3:
		return mp200_fb_ioc_settrans3(info, arg);
	case SONY_NAVU_FBIO_GETDISP3:
		return mp200_fb_ioc_getdisp3(info, arg);
	case SONY_NAVU_FBIO_GETBASE3:
		return mp200_fb_ioc_getbase3(info, arg);


#else /* CONFIG_PGPF_FB_PND_EXT */
	case PGPF_FBIO_SET_LCD_STATUS:
		return mp200_fb_ioc_set_lcd_status(info, arg);
	case PGPF_FBIO_WAIT_VSYNC:
		return mp200_fb_ioc_wait_vsync(info, arg);

		/* L1 */
	case PGPF_FBIO_GUI_SET_ENABLED:
		return mp200_fb_ioc_gui_set_enabled(info, arg);
	case PGPF_FBIO_GUI_SET_TRANS:
		return mp200_fb_ioc_gui_set_trans(info, arg);

#ifdef CONFIG_PGPF_FB_LAYER2
		/* L2 */
	case PGPF_FBIO_PHOTO_SET_ENABLED:
		return mp200_fb_ioc_photo_set_enabled(info, arg);
	case PGPF_FBIO_PHOTO_SELECT_BUF:
		return mp200_fb_ioc_photo_select_buf(info, arg);
	case PGPF_FBIO_PHOTO_SET_FRAME:
		return mp200_fb_ioc_photo_set_frame(info, arg);
	case PGPF_FBIO_PHOTO_GET_FRAME:
		return mp200_fb_ioc_photo_get_frame(info, arg);
	case PGPF_FBIO_PHOTO_SET_FORMAT:
		return mp200_fb_ioc_photo_set_format(info, arg);
	case PGPF_FBIO_PHOTO_GET_FORMAT:
		return mp200_fb_ioc_photo_get_format(info, arg);
	case PGPF_FBIO_PHOTO_GET_BASE:
		return mp200_fb_ioc_photo_get_base(info, arg);
	case PGPF_FBIO_PHOTO_GET_OFFSET:
		return mp200_fb_ioc_photo_get_offset(info, arg);
#endif /* CONFIG_PGPF_FB_LAYER2 */
#endif /* CONFIG_PGPF_FB_PND_EXT */

#endif /* CONFIG_MACH_PGPF */

#ifndef CONFIG_PGPF_FB_UX_EXT
	case MP200_FB_CHKSCRN:
		/* check frame buffer status        */
		return mp200_fb_ioc_chk_scrn(info, arg);

	case MP200_FB_GET_MODES:
		/* get frame buffer infomation      */
		return mp200_fb_ioc_get_modes(info, arg);

	case MP200_FB_SET_MODES:
		/* Set or Update frame buffer infomation   */
		return mp200_fb_ioc_set_modes(info, cmd, arg);

	case MP200_FB_UPDATE_SCRN:
		return mp200_fb_ioc_update_scrn(info, cmd, arg);

	case MP200_FB_UPDATE_TIMER:
		/* update timer infomation          */
		return mp200_fb_ioc_update_timer(info, arg);
#endif /* !CONFIG_PGPF_FB_UX_EXT */

#ifdef CONFIG_FB_MP200_NTS
        case MP200_FB_SET_OUTPUT:
		return mp200_fb_ioc_set_output( info, arg );

        case MP200_FB_GET_OUTPUT:
		return mp200_fb_ioc_get_output( info, arg );
#endif /* CONFIG_FB_MP200_NTS */

	default:
		printk_dbg((_DEBUG_FB & 0x01), "ioctl(*** unknown request ***)\n");
		return -ENOIOCTLCMD;
	}
}

#ifdef CONFIG_MACH_PGPF
#ifdef CONFIG_PGPF_FB_PND_EXT
static int mp200_fb_ioc_disp(struct fb_info *info, unsigned long arg)
{
	int ret = mp200_fb_set_lcd_status(info, arg);
	printk_dbg((_DEBUG_FB & 0x80), "SONY_NAVU_FBIO_DISP: %u \n", ret);
	return ret;
}

static int mp200_fb_ioc_layer0(struct fb_info* info, unsigned long arg)
{
	int ret = 0;
	mp200_fb_par *par = (mp200_fb_par *)info->par;
	
	unsigned int mode;
	
	if (get_user(mode, (unsigned int *)arg)) {
		return -EFAULT;
	}
	printk_dbg((_DEBUG_FB & 0x80), "SONY_NAVU_FBIO_LAYER0: %u \n", mode);
	if (mode == 0 || mode == 1) {
		if (fb_data[par->devflag].BaseFrame.Status != mode) {
			if (down_interruptible(&par->sem_fb_image_info)) {
				return -EBUSY;
			}
			fb_data[par->devflag].bg_image_info.control = mode;
			fb_data[par->devflag].BaseFrame.Status = mode;
			ret = mp200_fb_set_image(&fb_data[par->devflag].fb_image_info, &fb_data[par->devflag].bg_image_info, NULL, NULL, par->devflag);
			up(&par->sem_fb_image_info);
		}
	}

	if (ret == 0) {
		ret = fb_data[par->devflag].bg_image_info.control;
	}
	
	return ret;
}

static int mp200_fb_ioc_setscroll0(struct fb_info *info, unsigned long arg)
{
	int ret = 0;
	mp200_fb_par *par = (mp200_fb_par *)info->par;
	SONY_NAVU_SETSCROLL_FLIP user = {0};

	if (copy_from_user(&user, (SONY_NAVU_SETSCROLL *)arg, sizeof(SONY_NAVU_SETSCROLL0))) {
		return -EFAULT;
	}
	printk_dbg((_DEBUG_FB & 0x80), "SONY_NAVU_FBIO_SETSCROLL0: %u, %u, %d, %d\n", user.FrameX, user.FrameY, user.SpeedFrameX, user.SpeedFrameY);

	ret = mp200_check_scroll(&fb_data[par->devflag].BaseFrame, &user);
	
	if (ret == 0) {
		if (down_interruptible(&par->sem_fb_image_info)) {
			return -EBUSY;
		}
		fb_data[par->devflag].BaseScroll.target.x = user.FrameX;
		fb_data[par->devflag].BaseScroll.target.y = user.FrameY;
		fb_data[par->devflag].BaseScroll.speed.x  = user.SpeedFrameX;
		fb_data[par->devflag].BaseScroll.speed.y  = user.SpeedFrameY;
		fb_data[par->devflag].BaseScroll.status   = SONY_NAVU_SCROLL_AUTO;
		mp200_auto_scroll(info, par->devflag);
		up(&par->sem_fb_image_info);
	} else {
		printk_err("invalid argument!\n");
	}
	
	return ret;
}

static int mp200_fb_ioc_setscroll_flip0(struct fb_info *info, unsigned long arg)
{
	int ret = 0;
	mp200_fb_par *par = (mp200_fb_par *)info->par;
	SONY_NAVU_SETSCROLL_FLIP user = {0};
	
	if (copy_from_user(&user, (SONY_NAVU_SETSCROLL_FLIP *)arg, sizeof(SONY_NAVU_SETSCROLL_FLIP0))) {
		return -EFAULT;
	}

	printk_dbg((_DEBUG_FB & 0x80), "SONY_NAVU_FBIO_SETSCROLL_FLIP0: %u, %u, %d, %d, %u, %u, %u\n", user.FrameX, user.FrameY, user.SpeedFrameX, user.SpeedFrameY, user.StartX, user.StartY, user.Flip);

	ret = mp200_check_scroll(&fb_data[par->devflag].BaseFrame, &user);
	if (ret == 0) {
		if (down_interruptible(&par->sem_fb_image_info)) {
			return -EBUSY;
		}
		fb_data[par->devflag].BaseScroll.target.x = user.FrameX;
		fb_data[par->devflag].BaseScroll.target.y = user.FrameY;
		fb_data[par->devflag].BaseScroll.speed.x  = user.SpeedFrameX;
		fb_data[par->devflag].BaseScroll.speed.y  = user.SpeedFrameY;
		if ((user.StartX != SONY_NAVU_FAR_LIMIT) || (user.StartY != SONY_NAVU_FAR_LIMIT)) {
			fb_data[par->devflag].BaseFrame.FrameX = user.StartX;
			fb_data[par->devflag].BaseFrame.FrameY = user.StartY;
		}
		fb_data[par->devflag].BaseScroll.flip     = user.Flip;
		fb_data[par->devflag].BaseScroll.status   = SONY_NAVU_SCROLL_AUTO;
		mp200_auto_scroll(info, par->devflag);
		up(&par->sem_fb_image_info);
	} else {
		printk_err("invalid argument\n");
	}
	
	return ret;
}

static int mp200_fb_ioc_getscroll0(struct fb_info *info, unsigned long arg)
{
	int ret = 0;
	mp200_fb_par *par = (mp200_fb_par *)info->par;
	SONY_NAVU_GETSCROLL *user, local;
	
	local.FrameX = fb_data[par->devflag].BaseFrame.FrameX;
	local.FrameY = fb_data[par->devflag].BaseFrame.FrameY;
	local.Flag   = fb_data[par->devflag].BaseScroll.status;
	
	printk_dbg((_DEBUG_FB & 0x80), "SONY_NAVU_FBIO_GETSCROLL0: %u, %u, 0x%08x\n", local.FrameX, local.FrameY, local.Flag);

	if (get_user(user, (SONY_NAVU_GETSCROLL **)arg)) {
		return -EFAULT;
	}
	if (copy_to_user(user, &local, sizeof(SONY_NAVU_GETSCROLL))) {
		return -EFAULT;
	}

	return ret;
}

static int mp200_fb_ioc_selbuf0(struct fb_info *info, unsigned long arg)
{
	int ret = 0;
	mp200_fb_par *par = (mp200_fb_par *)info->par;

	unsigned int mode;
	
	if (get_user(mode, (unsigned int *)arg)) {
		return -EFAULT;
	}
	if ((_DEBUG_FB & 0x40) || mode < 2) {
		printk_dbg((_DEBUG_FB & 0x80), "SONY_NAVU_FBIO_SELBUF0: %u\n", mode);
	}

	if ((mode == 0 || mode == 1) &&
		fb_data[par->devflag].BaseFrame.Flip != mode) {
		if (down_interruptible(&par->sem_fb_image_info)) {
			return -EBUSY;
		}
		fb_data[par->devflag].BaseScroll.flip = mode;
		fb_data[par->devflag].BaseScroll.status = SONY_NAVU_SCROLL_AUTO;
		mp200_auto_scroll(info, par->devflag);
		up(&par->sem_fb_image_info);
	}

	if (fb_data[par->devflag].BaseFrame.Status == 1 || mode < 2) {
		ret = fb_data[par->devflag].BaseScroll.flip;
	} else {
		/* not displayed */
		ret = 0xFFFFFFFF;
	}

	return ret;
}

static int mp200_fb_ioc_getframe0(struct fb_info *info, unsigned long arg)
{
	int ret = 0;
	mp200_fb_par *par = (mp200_fb_par *)info->par;
	SONY_NAVU_DISPSETTING0* user, local;
	
	local.FrameWidth  = fb_data[par->devflag].bg_image_info.image_data.hsize;
	local.FrameHeight = fb_data[par->devflag].bg_image_info.image_data.vsize;

	printk_dbg((_DEBUG_FB & 0x80), "SONY_NAVU_FBIO_GETFRAME0: %u, %u\n", local.FrameWidth, local.FrameHeight);
	
	if (get_user(user, (SONY_NAVU_DISPSETTING0 **)arg)) {
		return -EFAULT;
	}
	if (copy_to_user(user, &local, sizeof(SONY_NAVU_DISPSETTING0))) {
		return -EFAULT;
	}

	return ret;
}

static int mp200_fb_ioc_getbase0(struct fb_info *info, unsigned long arg)
{
	int ret = 0;
	unsigned int page;

	if (get_user(page, (unsigned int *)arg)) {
		return -EFAULT;
	}
	switch (page) {
	case 0:
		ret = BASE_A_OFFSET;
		printk_dbg((_DEBUG_FB & 0x80), "SONY_NAVU_FBIO_GETBASE0: 0x%08x\n", ret);
		break;
	case 1:
		ret = BASE_B_OFFSET;
		printk_dbg((_DEBUG_FB & 0x80), "SONY_NAVU_FBIO_GETBASE0: 0x%08x\n", ret);
		break;
	default:
		printk_err("invalid argument!\n");
		ret = -EINVAL;
		break;
	}
	
	return ret;
}

static int mp200_fb_ioc_waitvsync(struct fb_info *info, unsigned long arg)
{
	printk_dbg((_DEBUG_FB & 0x80), "SONY_NAVU_FBIO_WAITVSYNC\n");
	return mp200_fb_wait_vsync(info, arg);
}


#ifdef CONFIG_PGPF_FB_LAYER2
static int mp200_fb_ioc_layer2(struct fb_info *info, unsigned long arg)
{
	int ret = 0;
	mp200_fb_par *par = (mp200_fb_par *)info->par;
	unsigned int mode;

	if (get_user(mode, (unsigned int *)arg)) {
		return -EFAULT;
	}
	printk_dbg((_DEBUG_FB & 0x80), "SONY_NAVU_FBIO_LAYER2: %u\n", mode);
	switch (mode) {
	case 0: /* disable */
	case 1: /* enable */
		if (fb_data[par->devflag].SubFrame.Status != mode) {
			if (down_interruptible(&par->sem_fb_image_info)) {
				return -EBUSY;
			}
			switch (fb_data[par->devflag].SubFrame.Flip) {
			case 0:
			case 1:
				fb_data[par->devflag].l2_image_info.control = mode;
				break;
			}
			ret = mp200_fb_set_image(&fb_data[par->devflag].fb_image_info, NULL, &fb_data[par->devflag].l2_image_info, NULL, par->devflag);
			up(&par->sem_fb_image_info);
			if (ret == 0) {
				fb_data[par->devflag].SubFrame.Status = mode;
			}
		}
		break;
	default: /* return current status */
		break;
	}
	if (ret == 0) {
		ret = fb_data[par->devflag].SubFrame.Status;
	}
	
	return ret;
}

static int mp200_fb_ioc_setscroll2(struct fb_info *info, unsigned long arg)
{
	int ret = 0;
	mp200_fb_par *par = (mp200_fb_par *)info->par;
	SONY_NAVU_SETSCROLL_FLIP user = {0};

	if (copy_from_user(&user, (SONY_NAVU_SETSCROLL *)arg, sizeof(SONY_NAVU_SETSCROLL))) {
		return -EFAULT;
	}
	printk_dbg((_DEBUG_FB & 0x80), "SONY_NAVU_FBIO_SETSCROLL2: %u, %u, %d, %d\n", user.FrameX, user.FrameY, user.SpeedFrameX, user.SpeedFrameY);

	ret = mp200_check_scroll(&fb_data[par->devflag].SubFrame, &user);

	if (ret == 0) {
		if (down_interruptible(&par->sem_fb_image_info)) {
			return -EBUSY;
		}
		fb_data[par->devflag].SubScroll.target.x = user.FrameX;
		fb_data[par->devflag].SubScroll.target.y = user.FrameY;
		fb_data[par->devflag].SubScroll.speed.x  = user.SpeedFrameX;
		fb_data[par->devflag].SubScroll.speed.y  = user.SpeedFrameY;
		fb_data[par->devflag].SubScroll.status   = SONY_NAVU_SCROLL_AUTO;
		mp200_auto_scroll(info, par->devflag);
		up(&par->sem_fb_image_info);
	} else {
		printk_err("invalid argument!\n");
	}
	
	return ret;
}

static int mp200_fb_ioc_setscroll_flip2(struct fb_info *info, unsigned long arg)
{
	int ret = 0;
	mp200_fb_par *par = (mp200_fb_par *)info->par;
	SONY_NAVU_SETSCROLL_FLIP user = {0};
	
	if (copy_from_user(&user, (SONY_NAVU_SETSCROLL_FLIP *)arg, sizeof(SONY_NAVU_SETSCROLL_FLIP0))) {
		return -EFAULT;
	}

	printk_dbg((_DEBUG_FB & 0x80), "SONY_NAVU_FBIO_SETSCROLL_FLIP2: %u, %u, %d, %d, %u, %u, %u\n", user.FrameX, user.FrameY, user.SpeedFrameX, user.SpeedFrameY, user.StartX, user.StartY, user.Flip);

	ret = mp200_check_scroll(&fb_data[par->devflag].SubFrame, &user);
	if (ret == 0) {
		if (down_interruptible(&par->sem_fb_image_info)) {
			return -EBUSY;
		}
		fb_data[par->devflag].SubScroll.target.x = user.FrameX;
		fb_data[par->devflag].SubScroll.target.y = user.FrameY;
		fb_data[par->devflag].SubScroll.speed.x  = user.SpeedFrameX;
		fb_data[par->devflag].SubScroll.speed.y  = user.SpeedFrameY;
		if ((user.StartX != SONY_NAVU_FAR_LIMIT) || (user.StartY != SONY_NAVU_FAR_LIMIT)) {
			fb_data[par->devflag].SubFrame.FrameX = user.StartX;
			fb_data[par->devflag].SubFrame.FrameY = user.StartY;
		}
		fb_data[par->devflag].SubScroll.flip     = user.Flip;
		fb_data[par->devflag].SubScroll.status   = SONY_NAVU_SCROLL_AUTO;
		mp200_auto_scroll(info, par->devflag);
		up(&par->sem_fb_image_info);
	} else {
		printk_err("invalid argument\n");
	}
	
	return ret;
}

static int mp200_fb_ioc_getscroll2(struct fb_info *info, unsigned long arg)
{
	int ret = 0;
	mp200_fb_par *par = (mp200_fb_par *)info->par;
	SONY_NAVU_GETSCROLL *user, local;
	
	local.FrameX = fb_data[par->devflag].SubFrame.FrameX;
	local.FrameY = fb_data[par->devflag].SubFrame.FrameY;
	local.Flag   = fb_data[par->devflag].SubScroll.status;
	
	printk_dbg((_DEBUG_FB & 0x80), "SONY_NAVU_FBIO_GETSCROLL2: %u, %u, 0x%08x\n", local.FrameX, local.FrameY, local.Flag);

	if (get_user(user, (SONY_NAVU_GETSCROLL **)arg)) {
		return -EFAULT;
	}
	if (copy_to_user(user, &local, sizeof(SONY_NAVU_GETSCROLL))) {
		return -EFAULT;
	}

	return ret;
}

static int mp200_fb_ioc_selbuf2(struct fb_info *info, unsigned long arg)
{
	int ret = 0;
	mp200_fb_par *par = (mp200_fb_par *)info->par;
	unsigned int mode;

	if (get_user(mode, (unsigned int *)arg)) {
		return -EFAULT;
	}
	if ((_DEBUG_FB & 0x40) || mode < 3) {
		printk_dbg((_DEBUG_FB & 0x80), "SONY_NAVU_FBIO_SELBUF2: %u\n",mode);
	}
	if ((mode == 0 || mode == 1) &&
		fb_data[par->devflag].SubFrame.Flip != mode) {
		if (down_interruptible(&par->sem_fb_image_info)) {
			return -EBUSY;
		}
		fb_data[par->devflag].SubScroll.flip = mode;
		fb_data[par->devflag].SubScroll.status = SONY_NAVU_SCROLL_AUTO;
		mp200_auto_scroll(info, par->devflag);
		up(&par->sem_fb_image_info);
	}
	if (fb_data[par->devflag].SubFrame.Status == 1 || mode < 2) {
		ret = fb_data[par->devflag].SubScroll.flip;
	} else {
		/* not displayed */
		ret = 0xFFFFFFFF;
	}

	return ret;
}

static int mp200_fb_ioc_setdisp2(struct fb_info *info, unsigned long arg)
{
	int ret = 0;
	mp200_fb_par *par = (mp200_fb_par *)info->par;
	SONY_NAVU_DISPSETTING user = {0};
	frame_info frame;

	if (copy_from_user(&user, (SONY_NAVU_DISPSETTING*)arg, sizeof(SONY_NAVU_DISPSETTING))) {
		return -EFAULT;
	}
	printk_dbg((_DEBUG_FB & 0x80), "SONY_NAVU_FBIO_SETDISP2: %u, %u, %u, %u, %u, %u, (%u), (%u)\n", user.DispX, user.DispY, user.DispWidth, user.DispHeight, user.FrameX, user.FrameY);

	if ((user.FrameWidth * user.FrameHeight * SUB_BPP / 8) > SUBBUF_LENGTH) {
		printk_err("Frame parameters are invalid!\n");
		return -EINVAL;
	}

	frame = fb_data[par->devflag].SubFrame;
	frame.FrameWidth = user.FrameWidth;
	frame.FrameHeight = user.FrameHeight;

	ret = mp200_check_frame(&frame, &user);

	if (ret == 0) {
		if (down_interruptible(&par->sem_fb_image_info)) {
			return -EBUSY;
		}
		fb_data[par->devflag].SubFrame.DispX
			= fb_data[par->devflag].l2_image_info.screen_data.x
			= user.DispX;
		fb_data[par->devflag].SubFrame.DispY
			= fb_data[par->devflag].l2_image_info.screen_data.y
			= user.DispY;
		
		fb_data[par->devflag].SubFrame.DispWidth 
			= fb_data[par->devflag].l2_image_info.screen_data.hsize 
			= user.DispWidth;
		fb_data[par->devflag].SubFrame.DispHeight
			= fb_data[par->devflag].l2_image_info.screen_data.vsize
			= user.DispHeight;
		
		fb_data[par->devflag].SubFrame.FrameWidth
			= fb_data[par->devflag].l2_image_info.image_data.hsize
			= user.FrameWidth;
		fb_data[par->devflag].SubFrame.FrameHeight
			= fb_data[par->devflag].l2_image_info.image_data.vsize
			= user.FrameHeight;

		fb_data[par->devflag].SubScroll.target.x = user.FrameX;
		fb_data[par->devflag].SubScroll.target.y = user.FrameY;
		fb_data[par->devflag].SubScroll.speed.x  = SONY_NAVU_SPEED_WARP;
		fb_data[par->devflag].SubScroll.speed.y  = SONY_NAVU_SPEED_WARP;
		fb_data[par->devflag].SubScroll.status   = SONY_NAVU_SCROLL_AUTO;

		mp200_auto_scroll(info, par->devflag);
		up(&par->sem_fb_image_info);
	} else {
		printk_err("invalid argument!\n");
	}
	return ret;
}

static int mp200_fb_ioc_getdisp2(struct fb_info *info, unsigned long arg)
{
	int ret = 0;
	mp200_fb_par *par = (mp200_fb_par *)info->par;
	SONY_NAVU_DISPSETTING* user, local;

	local.DispX      = fb_data[par->devflag].l2_image_info.screen_data.x;
	local.DispY      = fb_data[par->devflag].l2_image_info.screen_data.y;

	local.DispWidth  = fb_data[par->devflag].l2_image_info.screen_data.hsize;
	local.DispHeight = fb_data[par->devflag].l2_image_info.screen_data.vsize;

	local.FrameX     = fb_data[par->devflag].l2_image_info.image_data.x;
	local.FrameY     = fb_data[par->devflag].l2_image_info.image_data.y;

	local.FrameWidth = fb_data[par->devflag].l2_image_info.image_data.hsize;
	local.FrameHeight = fb_data[par->devflag].l2_image_info.image_data.vsize;

	printk_dbg((_DEBUG_FB & 0x80), 
			   "SONY_NAVU_FBIO_GETDISP2: %u, %u, %u, %u, %u, %u, %u, %u\n", 
			   local.DispX, local.DispY, 
			   local.DispWidth, local.DispHeight,
			   local.FrameX, local.FrameY,
			   local.FrameWidth, local.FrameHeight
		);

	if (get_user(user, (SONY_NAVU_DISPSETTING**)arg)) {
		return -EFAULT;
	}
	if (copy_to_user(user, &local, sizeof(SONY_NAVU_DISPSETTING))) {
		return -EFAULT;
	}

	return ret;
}

static int mp200_fb_ioc_setformat2(struct fb_info *info, unsigned long arg)
{
	int ret = 0;
	mp200_fb_par *par = (mp200_fb_par *)info->par;

	SONY_NAVU_COLOR_FORMAT user = {0};
	uint32_t imc_color_fmt = 1; /* default: RGB565 */

	if (copy_from_user(&user, (SONY_NAVU_COLOR_FORMAT*)arg, sizeof(SONY_NAVU_COLOR_FORMAT))) {
		return -EFAULT;
	}
	printk_dbg((_DEBUG_FB & 0x80), "SONY_NAVU_FBIO_SETFORMAT2: 0x%04x, 0x%04x\n", user.type, user.bytelane);

	switch (user.type) {
	case SONY_NAVU_COLOR_FORMAT_RGB666:
		imc_color_fmt = IMC_Lx_FORMAT_RGB666;
		break;
	case SONY_NAVU_COLOR_FORMAT_RGB565:
		imc_color_fmt = IMC_Lx_FORMAT_RGB565;
		break;
	case SONY_NAVU_COLOR_FORMAT_YUV422Px:
		imc_color_fmt = IMC_Lx_FORMAT_YUV422Px;
		break;
	case SONY_NAVU_COLOR_FORMAT_YUV422Pl2:
		imc_color_fmt = IMC_Lx_FORMAT_YUV422Pl2;
		break;
	case SONY_NAVU_COLOR_FORMAT_YUV422Pl:
		imc_color_fmt = IMC_Lx_FORMAT_YUV422Pl;
		break;
	case SONY_NAVU_COLOR_FORMAT_YUV420Pl2:
		imc_color_fmt = IMC_Lx_FORMAT_YUV420Pl2;
		break;
	case SONY_NAVU_COLOR_FORMAT_YUV420Pl:
		imc_color_fmt = IMC_Lx_FORMAT_YUV420Pl;
		break;
	default:
		printk_err("not supported format!\n");
		return -EINVAL;
	}

	if (down_interruptible(&par->sem_fb_image_info)) {
		return -EBUSY;
	}

	fb_data[par->devflag].l2_image_info.yuvfmt = imc_color_fmt;
	fb_data[par->devflag].SubScroll.speed.x    = SONY_NAVU_SPEED_WARP;
	fb_data[par->devflag].SubScroll.speed.y    = SONY_NAVU_SPEED_WARP;
	fb_data[par->devflag].SubScroll.status     = SONY_NAVU_SCROLL_AUTO;
	mp200_auto_scroll(info, par->devflag);

	up(&par->sem_fb_image_info);

	return ret;
}

static int mp200_fb_ioc_getformat2(struct fb_info *info, unsigned long arg)
{
	int ret = 0;
	mp200_fb_par *par = (mp200_fb_par *)info->par;
	SONY_NAVU_COLOR_FORMAT* user, local;
	local.type = fb_data[par->devflag].l2_image_info.yuvfmt;

	if (local.type == IMC_Lx_FORMAT_YUV422Px) {
		local.bytelane = IMC_L2x_BYTELANE_422PX_YUYV;
	} else {
		local.bytelane = IMC_L2x_BYTELANE_INIT;
	}

	printk_dbg((_DEBUG_FB & 0x80), 
			   "SONY_NAVU_FBIO_GETFORMAT2: 0x%04x, 0x%04x\n", 
			   local.type, local.bytelane
		);

	if (get_user(user, (SONY_NAVU_COLOR_FORMAT**)arg)) {
		return -EFAULT;
	}
	if (copy_to_user(user, &local, sizeof(SONY_NAVU_COLOR_FORMAT))) {
		return -EFAULT;
	}

	return ret;
}

static int mp200_fb_ioc_getbase2(struct fb_info *info, unsigned long arg)
{
	int ret = mp200_fb_l2_get_address_base(info, arg);
	printk_dbg((_DEBUG_FB & 0x80), "SONY_NAVU_FBIO_GETBASE2: 0x%08x\n", ret);
	return ret;
}

static int mp200_fb_ioc_getaddroffset2(struct fb_info *info, unsigned long arg)
{
	int ret = 0;
	yuv_addr offset;
	SONY_NAVU_ADDR_OFFSET* user, local;

	ret = mp200_fb_l2_get_address_offset(info, &offset);

	if (ret == 0) {
		local.yrgbaddr = offset.yrgbaddr;
		local.uvaddr   = offset.uvaddr;
		local.vaddr    = offset.vaddr;
		printk_dbg((_DEBUG_FB & 0x80), "SONY_NAVU_FBIO_GETADDROFFSET2: 0x%08x, 0x%08x, 0x%08x\n", local.yrgbaddr, local.uvaddr, local.vaddr);
		if (get_user(user, (SONY_NAVU_ADDR_OFFSET**)arg)) {
			return -EFAULT;
		}
		if (copy_to_user(user, &local, sizeof(SONY_NAVU_ADDR_OFFSET))) {
			return -EFAULT;
		}
	}
	return ret;
}
#endif /* CONFIG_PGPF_FB_LAYER2 */

static int mp200_fb_ioc_layer1(struct fb_info *info, unsigned long arg)
{
	int ret = 0;
	mp200_fb_par *par = (mp200_fb_par *)info->par;
	unsigned int mode;

	if (get_user(mode, (unsigned int *)arg)) {
		return -EFAULT;
	}
	printk_dbg((_DEBUG_FB & 0x80), "SONY_NAVU_FBIO_LAYER1: %u\n", mode);
	switch (mode) {
	case 0: /* disable */
	case 1: /* enable */
		if (fb_data[par->devflag].OverlayFrame.Status != mode) {
			if (down_interruptible(&par->sem_fb_image_info)) {
				return -EBUSY;
			}
			switch (fb_data[par->devflag].OverlayFrame.Flip) {
			case 0:
			case 1:
				fb_data[par->devflag].fb_image_info.control = mode;
				if (mode) {
					fb_data[par->devflag].console_image_info.control = 0;
				}
				break;
			case 2:
				fb_data[par->devflag].fb_image_info.control = mode;
				fb_data[par->devflag].console_image_info.control = mode;
				break;
			}
			ret = mp200_fb_set_image(&fb_data[par->devflag].fb_image_info, NULL, NULL, &fb_data[par->devflag].console_image_info, par->devflag);
			up(&par->sem_fb_image_info);
			if (ret == 0) {
				fb_data[par->devflag].OverlayFrame.Status = mode;
			}
		}
		break;
	default: /* return current status */
		break;
	}

	if (ret == 0) {
		ret = fb_data[par->devflag].OverlayFrame.Status;
	}
	
	return ret;
}

static int mp200_fb_ioc_selbuf1(struct fb_info *info, unsigned long arg)
{
	int ret = 0;
	mp200_fb_par *par = (mp200_fb_par *)info->par;
	unsigned int mode;
	
	if (get_user(mode, (unsigned int *)arg)) {
		return -EFAULT;
	}
	if ((_DEBUG_FB & 0x40) || mode < 3) {
		printk_dbg((_DEBUG_FB & 0x80), "SONY_NAVU_FBIO_SELBUF1: %u\n",mode);
	}
	if (fb_data[par->devflag].OverlayFrame.Flip != mode) {
		if (down_interruptible(&par->sem_fb_image_info)) {
			return -EBUSY;
		}
		switch (mode) {
		case 0: /* GUI Buffer0 */
		case 1: /* GUI Buffer1 */
			set_image_info_to_LCD(mode, info);
			fb_data[par->devflag].fb_image_info.control = 1;
			fb_data[par->devflag].console_image_info.control = 0;
			fb_data[par->devflag].iNextDispPage = mode;
			break;
		case 2: /* Linux Console */
			fb_data[par->devflag].console_image_info.control = 1;
			break;
		default: /* return current buffer */
			break;
		}
		if (mode < 3) {
			fb_data[par->devflag].OverlayFrame.Flip = mode;
			if (fb_data[par->devflag].OverlayFrame.Status == 1) {
				ret = mp200_fb_set_image(&fb_data[par->devflag].fb_image_info, NULL, NULL, &fb_data[par->devflag].console_image_info, par->devflag);
				if (ret) {
					up(&par->sem_fb_image_info);
					return ret;
				}
			}
		}
		up(&par->sem_fb_image_info);
	}
	if (fb_data[par->devflag].OverlayFrame.Status == 1 || mode < 3) {
		ret = fb_data[par->devflag].OverlayFrame.Flip;
	} else {
		/* not displayed */
		ret = 0xFFFFFFFF;
	}

	return ret;
}

static int mp200_fb_ioc_getdisp1(struct fb_info *info, unsigned long arg)
{
	int ret = 0;
	mp200_fb_par *par = (mp200_fb_par *)info->par;
	SONY_NAVU_DISPSETTING1 *user, local;

	local.DispX 
		= local.FrameX
		= fb_data[par->devflag].fb_image_info.image_data.x;
	local.DispY
		= local.FrameY
		= fb_data[par->devflag].fb_image_info.image_data.y;
	
	local.DispWidth 
		= fb_data[par->devflag].fb_image_info.image_data.hsize;
	local.DispHeight 
		= fb_data[par->devflag].fb_image_info.image_data.vsize;
	
	printk_dbg((_DEBUG_FB & 0x80), 
			   "SONY_NAVU_FBIO_GETDISP1: %u, %u, %u, %u, %u, %u\n", 
			   local.DispX, local.DispY, 
			   local.DispWidth, local.DispHeight, 
			   local.FrameX, local.FrameY
		);
	
	if (get_user(user, (SONY_NAVU_DISPSETTING1**)arg)) {
		return -EFAULT;
	}
	if (copy_to_user(user, &local, sizeof(SONY_NAVU_DISPSETTING1))) {
		return -EFAULT;
	}

	return ret;
}

static int mp200_fb_ioc_getbase1(struct fb_info *info, unsigned long arg)
{
	int ret = 0;
	unsigned int mode;
		
	if (get_user(mode, (unsigned int *)arg)) {
		return -EFAULT;
	}
	
	switch (mode) {
	case 0:
		ret = DISPBUF_A_OFFSET;
		printk_dbg((_DEBUG_FB & 0x80), "SONY_NAVU_FBIO_GETBASE1: 0x%08x\n", ret);
		break;
	case 1:
		ret = DISPBUF_B_OFFSET;
		printk_dbg((_DEBUG_FB & 0x80), "SONY_NAVU_FBIO_GETBASE1: 0x%08x\n", ret);
		break;
	case 2:
		ret = CONSOLE_OFFSET;
		printk_dbg((_DEBUG_FB & 0x80), "SONY_NAVU_FBIO_GETBASE1: 0x%08x\n", ret);
		break;
	default:
		printk_err("invalid argument!\n");
		ret = -EINVAL;
		break;
	}
	
	return ret;
}

static int mp200_fb_ioc_settrans3(struct fb_info *info, unsigned long arg)
{
	int ret = 0;
	mp200_fb_par *par = (mp200_fb_par *)info->par;
	unsigned int alpha;

	if (get_user(alpha, (unsigned int *)arg)) {
		return -EFAULT;
	}
	printk_dbg((_DEBUG_FB & 0x80), "SONY_NAVU_FBIO_SETTRANS3: %u\n", alpha);
	if (alpha >= 0 && alpha <= 255) {
		if (down_interruptible(&par->sem_fb_image_info)) {
			return -EBUSY;
		}
		fb_data[par->devflag].console_image_info.alpha = alpha;
		ret = mp200_fb_set_image(&fb_data[par->devflag].fb_image_info, NULL, NULL, &fb_data[par->devflag].console_image_info, par->devflag);
		up(&par->sem_fb_image_info);
	}

	if (ret == 0) {
		ret = fb_data[par->devflag].console_image_info.alpha;
	}

	return ret;
}

static int mp200_fb_ioc_getbase3(struct fb_info *info, unsigned long arg)
{
	int ret = 0;
	unsigned int mode;
	
	if (get_user(mode, (unsigned int *)arg)) {
		return -EFAULT;
	}
	
	if (mode == 0) {
		ret = CONSOLE_OFFSET;
		printk_dbg((_DEBUG_FB & 0x80), "SONY_NAVU_FBIO_GETBASE3: 0x%08x\n", ret);
	} else {
		printk_err("invalid argument!\n");
		ret = -EINVAL;
	}

	return ret;
}

static int mp200_fb_ioc_getdisp3(struct fb_info *info, unsigned long arg)
{
	int ret = 0;
	mp200_fb_par *par = (mp200_fb_par *)info->par;
	SONY_NAVU_DISPSETTING *user, local;
	
	local.DispX
		= local.FrameX
		= fb_data[par->devflag].console_image_info.image_data.x;
	local.DispY 
		= local.FrameY
		= fb_data[par->devflag].console_image_info.image_data.y;

	local.DispWidth
		= local.FrameWidth
		= fb_data[par->devflag].console_image_info.image_data.hsize;
	local.DispHeight
		= local.FrameHeight
		= fb_data[par->devflag].console_image_info.image_data.vsize;

	printk_dbg((_DEBUG_FB & 0x80), "SONY_NAVU_FBIO_GETDISP3: %u, %u, %u, %u, %u, %u, %u, %u\n", 
			   local.DispX, local.DispY,
			   local.DispWidth, local.DispHeight,
			   local.FrameX, local.FrameY,
			   local.FrameWidth, local.FrameHeight
		);
	
	if (get_user(user, (SONY_NAVU_DISPSETTING**)arg)) {
		return -EFAULT;
	}
	if (copy_to_user(user, &local, sizeof(SONY_NAVU_DISPSETTING))) {
		return -EFAULT;
	}

	return ret;
}

#else /* CONFIG_PGPF_FB_PND_EXT */
static int mp200_fb_ioc_set_lcd_status(struct fb_info *info, unsigned long arg)
{
	int ret = mp200_fb_set_lcd_status(info, arg);
	printk_dbg((_DEBUG_FB & 0x80), "PGPF_FBIO_SET_LCD_STATUS: %u \n", ret);
	return ret;
}

static int mp200_fb_ioc_wait_vsync(struct fb_info *info, unsigned long arg)
{
	printk_dbg((_DEBUG_FB & 0x80), "PGPF_FBIO_WAIT_VSYNC\n");
	return mp200_fb_wait_vsync(info, arg);
}

static int mp200_fb_ioc_gui_set_enabled(struct fb_info *info, unsigned long arg)
{
	int ret = 0;
	mp200_fb_par *par = (mp200_fb_par *)info->par;
	unsigned int mode;

	if (get_user(mode, (unsigned int *)arg)) {
		return -EFAULT;
	}
	printk_dbg((_DEBUG_FB & 0x80), "PGPF_FBIO_GUI_SET_ENABLED: %u\n", mode);
	switch (mode) {
	case 0: /* disable */
	case 1: /* enable */
		if (fb_data[par->devflag].fb_image_info.control != mode) {
			if (down_interruptible(&par->sem_fb_image_info)) {
				return -EBUSY;
			}
			fb_data[par->devflag].fb_image_info.control = mode;
			ret = mp200_fb_set_image(&fb_data[par->devflag].fb_image_info, NULL, NULL, NULL, par->devflag);
			up(&par->sem_fb_image_info);
		}
		break;
	default: /* return current status */
		break;
	}

	if (ret == 0) {
		ret = fb_data[par->devflag].fb_image_info.control;
	}
	
	return ret;
}

static int mp200_fb_ioc_gui_set_trans(struct fb_info *info, unsigned long arg)
{
	int ret = 0;
	mp200_fb_par *par = (mp200_fb_par *)info->par;

	pgpf_trans_info user = {0};

	if (copy_from_user(&user, (pgpf_trans_info*)arg, sizeof(pgpf_trans_info))) {
		return -EFAULT;
	}
	printk_dbg((_DEBUG_FB & 0x80), "PGPF_FBIO_GUI_SET_TRANS: %u, %u, %u\n", user.key_enable, user.key_color, user.alpha_value);

	if ((user.key_enable > 1) || (user.key_color & 0xffff0000) || 
		(user.alpha_value > 255)) {
		printk_err("invalid argument!\n");
		return -EINVAL;
	}

	if (down_interruptible(&par->sem_fb_image_info)) {
		return -EBUSY;
	}
	fb_data[par->devflag].fb_image_info.maskcolr = user.key_color;
	fb_data[par->devflag].fb_image_info.alpha = user.alpha_value;
	fb_data[par->devflag].fb_image_info.maskcolrflg = user.key_enable ? TC_COLOR_ENABLE : TC_COLOR_DISABLE;
	ret = mp200_fb_set_image(&fb_data[par->devflag].fb_image_info, NULL, NULL, NULL, par->devflag);
	up(&par->sem_fb_image_info);

	return ret;
}

#ifdef CONFIG_PGPF_FB_LAYER2
static int mp200_fb_ioc_photo_set_enabled(struct fb_info *info, unsigned long arg)
{
	int ret = 0;
	mp200_fb_par *par = (mp200_fb_par *)info->par;
	unsigned int mode;

	if (get_user(mode, (unsigned int *)arg)) {
		return -EFAULT;
	}
	printk_dbg((_DEBUG_FB & 0x80), "PGPF_FBIO_PHOTO_SET_ENABLED: %u\n", mode);
	switch (mode) {
	case 0: /* disable */
	case 1: /* enable */
		if (fb_data[par->devflag].l2_image_info.control != mode) {
			if (down_interruptible(&par->sem_fb_image_info)) {
				return -EBUSY;
			}
			fb_data[par->devflag].l2_image_info.control = mode;
			ret = mp200_fb_set_image(&fb_data[par->devflag].fb_image_info, NULL, &fb_data[par->devflag].l2_image_info, NULL, par->devflag);
			up(&par->sem_fb_image_info);
		}
		break;
	default: /* return current status */
		break;
	}

	if (ret == 0) {
		ret = fb_data[par->devflag].l2_image_info.control;
	}
	
	return ret;
}

static int mp200_fb_ioc_photo_select_buf(struct fb_info *info, unsigned long arg)
{
	int ret = 0;
	mp200_fb_par *par = (mp200_fb_par *)info->par;
	unsigned int mode;

	if (get_user(mode, (unsigned int *)arg)) {
		return -EFAULT;
	}
	if ((_DEBUG_FB & 0x40) || mode < 3) {
		printk_dbg((_DEBUG_FB & 0x80), "PGPF_FBIO_SELECT_BUF: %u\n",mode);
	}
	if ((mode == 0 || mode == 1) &&
		fb_data[par->devflag].L2Flip != mode) {
		if (down_interruptible(&par->sem_fb_image_info)) {
			return -EBUSY;
		}
		fb_data[par->devflag].L2Flip = mode;

		mp200_fb_l2_set_address(mode, par->devflag);

		ret = mp200_fb_set_image(&fb_data[par->devflag].fb_image_info, NULL, &fb_data[par->devflag].l2_image_info, NULL, par->devflag);
		up(&par->sem_fb_image_info);
	}
	if (ret == 0) {
		if (fb_data[par->devflag].l2_image_info.control == 1 || mode < 2) {
			ret = fb_data[par->devflag].L2Flip;
		} else {
			/* not displayed */
			ret = 0xFFFFFFFF;
		}
	}

	return ret;
}

static int mp200_fb_ioc_photo_set_frame(struct fb_info *info, unsigned long arg)
{
	int ret = 0;
	mp200_fb_par *par = (mp200_fb_par *)info->par;
	pgpf_frame_info user = {0};

	if (copy_from_user(&user, (pgpf_frame_info*)arg, sizeof(pgpf_frame_info))) {
		return -EFAULT;
	}
	printk_dbg((_DEBUG_FB & 0x80), "PGPF_FBIO_PHOTO_SET_FRAME: %u, %u, %u, %u, %u, %u, (%u), (%u)\n", user.screen_x, user.screen_y, user.screen_width, user.screen_height, user.frame_x, user.frame_y);

	if ((user.frame_width * user.frame_height * SUB_BPP / 8) > SUBBUF_LENGTH) {
		printk_err("Frame parameters are invalid!\n");
		return -EINVAL;
	}

	if ((user.screen_width > user.frame_width) ||
		(user.screen_height > user.frame_height) ||
		(user.frame_x > (user.frame_width - user.screen_width))|| 
		(user.frame_y > (user.frame_height - user.screen_height)) || 
		(user.screen_width > LCD_WIDTH) ||
		(user.screen_height > LCD_HEIGHT) ||
		(user.screen_x > (LCD_WIDTH - user.screen_width)) || 
		(user.screen_y > (LCD_HEIGHT - user.screen_height))) {
		printk_err("Frame parameters are invalid!\n");
		return -EINVAL;
	}

	if (down_interruptible(&par->sem_fb_image_info)) {
		return -EBUSY;
	}
	fb_data[par->devflag].l2_image_info.screen_data.x = user.screen_x;
	fb_data[par->devflag].l2_image_info.screen_data.y = user.screen_y;
	
	fb_data[par->devflag].l2_image_info.screen_data.hsize = user.screen_width;
	fb_data[par->devflag].l2_image_info.screen_data.vsize = user.screen_height;
	
	fb_data[par->devflag].l2_image_info.image_data.x = user.frame_x;
	fb_data[par->devflag].l2_image_info.image_data.y = user.frame_y;
	
	fb_data[par->devflag].l2_image_info.image_data.hsize = user.frame_width;
	fb_data[par->devflag].l2_image_info.image_data.vsize = user.frame_height;
	
	ret = mp200_fb_set_image(&fb_data[par->devflag].fb_image_info, NULL, &fb_data[par->devflag].l2_image_info, NULL, par->devflag);
	up(&par->sem_fb_image_info);

	return ret;
}

static int  mp200_fb_ioc_photo_get_frame(struct fb_info *info, unsigned long arg)
{
	int ret = 0;
	mp200_fb_par *par = (mp200_fb_par *)info->par;
	pgpf_frame_info* user, local;

	local.screen_x = fb_data[par->devflag].l2_image_info.screen_data.x;
	local.screen_y = fb_data[par->devflag].l2_image_info.screen_data.y;

	local.screen_width = fb_data[par->devflag].l2_image_info.screen_data.hsize;
	local.screen_height = fb_data[par->devflag].l2_image_info.screen_data.vsize;

	local.frame_x = fb_data[par->devflag].l2_image_info.image_data.x;
	local.frame_y = fb_data[par->devflag].l2_image_info.image_data.y;

	local.frame_width = fb_data[par->devflag].l2_image_info.image_data.hsize;
	local.frame_height = fb_data[par->devflag].l2_image_info.image_data.vsize;

	printk_dbg((_DEBUG_FB & 0x80), 
			   "PGPF_FBIO_PHOTO_GET_FRAME: %u, %u, %u, %u, %u, %u, %u, %u\n", 
			   local.screen_x, local.screen_y, 
			   local.screen_width, local.screen_height,
			   local.frame_x, local.frame_y,
			   local.frame_width, local.frame_height
		);

	if (get_user(user, (pgpf_frame_info**)arg)) {
		return -EFAULT;
	}
	if (copy_to_user(user, &local, sizeof(pgpf_frame_info))) {
		return -EFAULT;
	}

	return ret;
}

static int mp200_fb_ioc_photo_set_format(struct fb_info *info, unsigned long arg)
{
	int ret = 0;
	mp200_fb_par *par = (mp200_fb_par *)info->par;

	pgpf_color_format user = {0};
	uint32_t imc_color_fmt = 1;

	if (copy_from_user(&user, (pgpf_color_format*)arg, sizeof(pgpf_color_format))) {
		return -EFAULT;
	}
	printk_dbg((_DEBUG_FB & 0x80), "PGPF_FBIO_PHOTO_SET_FORMAT: 0x%04x, 0x%04x\n", user.type, user.bytelane);

	if (down_interruptible(&par->sem_fb_image_info)) {
		return -EBUSY;
	}

	switch (user.type) {
	case PGPF_COLOR_FORMAT_RGB666:
		imc_color_fmt = IMC_Lx_FORMAT_RGB666;
		break;
	case PGPF_COLOR_FORMAT_RGB565:
		imc_color_fmt = IMC_Lx_FORMAT_RGB565;
		break;
	case PGPF_COLOR_FORMAT_YUV422Px:
		imc_color_fmt = IMC_Lx_FORMAT_YUV422Px;
		break;
	case PGPF_COLOR_FORMAT_YUV422Pl2:
		imc_color_fmt = IMC_Lx_FORMAT_YUV422Pl2;
		break;
	case PGPF_COLOR_FORMAT_YUV422Pl:
		imc_color_fmt = IMC_Lx_FORMAT_YUV422Pl;
		break;
	case PGPF_COLOR_FORMAT_YUV420Pl2:
		imc_color_fmt = IMC_Lx_FORMAT_YUV420Pl2;
		break;
	case PGPF_COLOR_FORMAT_YUV420Pl:
		imc_color_fmt = IMC_Lx_FORMAT_YUV420Pl;
		break;
	default:
		printk_err("not supported format!\n");
		return -EINVAL;
	}

	fb_data[par->devflag].l2_image_info.yuvfmt = imc_color_fmt;

	mp200_fb_l2_set_address(fb_data[par->devflag].L2Flip, par->devflag);

	ret = mp200_fb_set_image(&fb_data[par->devflag].fb_image_info, NULL, &fb_data[par->devflag].l2_image_info, NULL, par->devflag);
	up(&par->sem_fb_image_info);

	return ret;
}

static int mp200_fb_ioc_photo_get_format(struct fb_info *info, unsigned long arg)
{
	int ret = 0;
	mp200_fb_par *par = (mp200_fb_par *)info->par;
	pgpf_color_format* user, local;
	local.type = fb_data[par->devflag].l2_image_info.yuvfmt;

	if (local.type == IMC_Lx_FORMAT_YUV422Px) {
		local.bytelane = IMC_L2x_BYTELANE_422PX_YUYV;
	} else {
		local.bytelane = IMC_L2x_BYTELANE_INIT;
	}

	printk_dbg((_DEBUG_FB & 0x80), 
			   "PGPF_FBIO_PHOTO_GET_FORMAT: 0x%04x, 0x%04x\n", 
			   local.type, local.bytelane
		);

	if (get_user(user, (pgpf_color_format**)arg)) {
		return -EFAULT;
	}
	if (copy_to_user(user, &local, sizeof(pgpf_color_format))) {
		return -EFAULT;
	}

	return ret;
}

static int mp200_fb_ioc_photo_get_base(struct fb_info *info, unsigned long arg)
{
	int ret = mp200_fb_l2_get_address_base(info, arg);
	printk_dbg((_DEBUG_FB & 0x80), "PGPF_FBIO_PHOTO_GET_BASE: 0x%08x\n", ret);
	return ret;
}

static int mp200_fb_ioc_photo_get_offset(struct fb_info *info, unsigned long arg)
{
	int ret = 0;
	yuv_addr offset;
	pgpf_yuv_addr* user, local;

	ret = mp200_fb_l2_get_address_offset(info, &offset);

	if (ret == 0) {
		local.yrgbaddr = offset.yrgbaddr;
		local.uvaddr   = offset.uvaddr;
		local.vaddr    = offset.vaddr;
		printk_dbg((_DEBUG_FB & 0x80), "PGPF_FBIO_PHOTO_GET_OFFSET: 0x%08x, 0x%08x, 0x%08x\n", local.yrgbaddr, local.uvaddr, local.vaddr);
		if (get_user(user, (pgpf_yuv_addr**)arg)) {
			return -EFAULT;
		}
		if (copy_to_user(user, &local, sizeof(pgpf_yuv_addr))) {
			return -EFAULT;
		}
	}
	return ret;
}
#endif /* CONFIG_PGPF_FB_LAYER2 */
#endif /* CONFIG_PGPF_FB_PND_EXT */

#ifdef CONFIG_PGPF_BACKLIGHT
#ifdef CONFIG_PGPF_NAVU2
static int mp200_fb_ioc_set_tpled(struct fb_info *info, unsigned long arg)
{
	int mode;
	if (get_user(mode, (unsigned int *)arg)) {
		return -EFAULT;
	}

	return mp200_fb_set_tpled(mode);
}
#endif /* CONFIG_PGPF_NAVU2 */
static int mp200_fb_ioc_set_brightness(struct fb_info *info, unsigned long arg)
{
	int brightness;
	if (get_user(brightness, (unsigned int *)arg)) {
		return -EFAULT;
	}

	return mp200_fb_set_brightness(brightness);
}

static int mp200_fb_ioc_get_brightness(struct fb_info *info, unsigned long arg)
{
	return mp200_fb_get_brightness();
}
#endif /* CONFIG_PGPF_BACKLIGHT */
#endif /* CONFIG_MACH_PGPF */

#ifdef CONFIG_PGPF_FB_PND_EXT

#endif /* CONFIG_PGPF_FB_PND_EXT */

#ifndef CONFIG_PGPF_FB_UX_EXT
/******************************************************************************
* MODULE   : mp200_fb_ioc_chk_scrn
* FUNCTION : frame buffer driver ioctl
* RETURN   :  0      : success
*            -EFAULT :
* NOTE     : none
* CREATE   : 2008.04.03 M.Haguro
* UPDATE   : 2008.12.10 J.Manabe
******************************************************************************/
static int mp200_fb_ioc_chk_scrn(struct fb_info *info, unsigned long arg)
{
#if (TIMEOUT_MSLEEP==0)
	int             iWaitTime  = 0;
	int             iTotalTime = 0;
	scrn_mode       FBScrnMode;
	mp200_fb_par   *par  = (mp200_fb_par *)info->par;
#else /* TIMEOUT_MSLEEP==1 */
	int             iTotalTime = 0;
	scrn_mode       FBScrnMode;
	struct timeval  tStartTime;
	struct timeval  tNowTime;
	mp200_fb_par   *par  = (mp200_fb_par *)info->par;

	/* get start time */
	do_gettimeofday(&tStartTime);
#endif
	printk_dbg((_DEBUG_FB & 0x01), "ioctl(CHKSCRN) <start>\n");

	down( &par->sem_tvmode );
	/* TVMODE Check */
	if( ( par->devflag == EM1_FB_DEVICE_NTS ) && ( tvmode == EM1_TV_MODE_OFF ) ){
		up( &par->sem_tvmode );
		return -EIO;
	}

	/* get scrn mode info */
	if(copy_from_user(&FBScrnMode, (scrn_mode *) arg, sizeof(scrn_mode))){
		up( &par->sem_tvmode );
		return -EFAULT;
	}

	/* check frame buffer status */
	FBScrnMode.page0 = chk_fb_status(fb_data[par->devflag].iFBStatus_A);
	FBScrnMode.page1 = chk_fb_status(fb_data[par->devflag].iFBStatus_B);

	/* if arg->timeout=0, then break */
	if(FBScrnMode.timeout <= 0){
		if(copy_to_user((scrn_mode *) arg, &FBScrnMode, sizeof(scrn_mode))){
			up( &par->sem_tvmode );
			return -EFAULT;
		}
		up( &par->sem_tvmode );
		return 0;
	}

	/* if both A and B states are "WAITING_FOR_ON_DISPLAY", */
	/*    then waits during the time specified by "timeout" */
	if( FBScrnMode.page0 == WAITING_FOR_ON_DISPLAY && FBScrnMode.page1 == WAITING_FOR_ON_DISPLAY ){
#if (TIMEOUT_MSLEEP==0)
		/* loop until timeout or enable write */
		do{
			/* timeout time (msec to jiffies) */
			iWaitTime = (RECHK_TIME + 1000/HZ-1) / (1000/HZ);

			wait_event_interruptible_timeout(par->wait_fb_chk_scrn, ( ( fb_data[par->devflag].iFBStatus_A == IS_NODATA )    || 
			                                                          ( fb_data[par->devflag].iFBStatus_A == ENABLE_WRITE ) ||
			                                                          ( fb_data[par->devflag].iFBStatus_B == IS_NODATA )    || 
			                                                          ( fb_data[par->devflag].iFBStatus_B == ENABLE_WRITE ) ), iWaitTime);

			iTotalTime += RECHK_TIME;

			/* re-check frame buffer status */
			FBScrnMode.page0 = chk_fb_status(fb_data[par->devflag].iFBStatus_A);
			FBScrnMode.page1 = chk_fb_status(fb_data[par->devflag].iFBStatus_B);

			/* when over timeout time, return */
			if(iTotalTime > FBScrnMode.timeout){
				break;
			}
		}
		while(FBScrnMode.page0 == WAITING_FOR_ON_DISPLAY && FBScrnMode.page1 == WAITING_FOR_ON_DISPLAY);
#else /* TIMEOUT_MSLEEP==1 */
		/* loop until timeout or enable write */
		do{
			/* sleep 10ms */
			msleep(RECHK_TIME);

			/* get time */
			do_gettimeofday(&tNowTime);
			if (tNowTime.tv_sec > tStartTime.tv_sec){
				iTotalTime = (tNowTime.tv_sec - tStartTime.tv_sec) * 1000;
				if (tNowTime.tv_usec > tStartTime.tv_usec){
					iTotalTime += (tNowTime.tv_usec - tStartTime.tv_usec) / 1000;
				}
				else{
					iTotalTime -= (tStartTime.tv_usec - tNowTime.tv_usec) / 1000;
				}
			}
			else{
				iTotalTime = (tNowTime.tv_usec - tStartTime.tv_usec) / 1000;
			}

			/* re-check frame buffer status */
			FBScrnMode.page0 = chk_fb_status(fb_data[par->devflag].iFBStatus_A);
			FBScrnMode.page1 = chk_fb_status(fb_data[par->devflag].iFBStatus_B);

			/* when over timeout time, return */
			if(iTotalTime > FBScrnMode.timeout){
				break;
			}
		}
		while(FBScrnMode.page0 == WAITING_FOR_ON_DISPLAY && FBScrnMode.page1 == WAITING_FOR_ON_DISPLAY);
#endif
	}
	printk_dbg((_DEBUG_FB & 0x08), "ioctl(CHKSCRN): A(%d) B(%d)\n", FBScrnMode.page0, FBScrnMode.page1);

	/* return scrn mode info */
	if(copy_to_user((scrn_mode *) arg, &FBScrnMode, sizeof(scrn_mode))){
		up( &par->sem_tvmode );
		return -EFAULT;
	}
	if (FBScrnMode.page0 == WAITING_FOR_ON_DISPLAY && FBScrnMode.page1 == WAITING_FOR_ON_DISPLAY){
		up( &par->sem_tvmode );
		return FBScrnMode.timeout;
	}

	up( &par->sem_tvmode );

	printk_dbg((_DEBUG_FB & 0x02), "ioctl(CHKSCRN) <end>\n");
	return 0;
}


/******************************************************************************
* MODULE   : mp200_fb_ioc_get_modes
* FUNCTION : frame buffer driver ioctl
* RETURN   :  0      : success
*            -EFAULT :
* NOTE     : none
* CREATE   : 2008.04.03 M.Haguro
* UPDATE   : 2008.12.10 J.Manabe
******************************************************************************/
static int mp200_fb_ioc_get_modes(struct fb_info *info, unsigned long arg)
{
	scrn_modes    FBScrnModes;
	mp200_fb_par *par  = (mp200_fb_par *)info->par;

	printk_dbg((_DEBUG_FB & 0x01), "ioctl(GET_MODES) <start>\n");

	down( &par->sem_tvmode );
	/* TVMODE Check */
	if( ( par->devflag == EM1_FB_DEVICE_NTS ) && ( tvmode == EM1_TV_MODE_OFF ) ){
		up( &par->sem_tvmode );
		return -EIO;
	}

	/* set now on display infomation */
	set_image_info_to_2DAPI(fb_data[par->devflag].iNowDispPage, &FBScrnModes, info);

	/* copy to user scrn mode infomation */
	if(copy_to_user((scrn_modes *) arg, &FBScrnModes, sizeof(scrn_modes))){
		up( &par->sem_tvmode );
		return -EFAULT;
	}
	
	up( &par->sem_tvmode );

	printk_dbg((_DEBUG_FB & 0x02), "(ioctl(GET_MODES) <end>\n");
	return 0;
}


/******************************************************************************
* MODULE   : mp200_fb_ioc_set_modes
* FUNCTION : frame buffer driver ioctl
* RETURN   :  0      : success
*            -1      :
*            -EBUSY  :
*            -ENXIO  :
*            -EFAULT :
* NOTE     : none
* CREATE   : 2008.04.03 M.Haguro
* UPDATE   :
******************************************************************************/
static int mp200_fb_ioc_set_modes(struct fb_info *info, unsigned int cmd, unsigned long arg)
{
	return mp200_fb_ioc_update_scrn(info, cmd, arg);
}


/******************************************************************************
* MODULE   : mp200_fb_ioc_update_scrn
* FUNCTION : frame buffer driver ioctl
* RETURN   :  0      : success
*            -1      :
*            -EBUSY  :
*            -ENXIO  :
*            -EFAULT :
* NOTE     : none
* CREATE   : 2008.04.03 M.Haguro
* UPDATE   : 2008.12.10 J.Manabe
******************************************************************************/
static int mp200_fb_ioc_update_scrn(struct fb_info *info, unsigned int cmd, unsigned long arg)
{
	scrn_modes    FBSrcnModes;
	mp200_fb_par *par = (mp200_fb_par *)info->par;

	printk_dbg((_DEBUG_FB & 0x01), "ioctl(UPDATE_SCRN) <start>\n");

	down( &par->sem_tvmode );
	/* TVMODE Check */
	if( ( par->devflag == EM1_FB_DEVICE_NTS ) && ( tvmode == EM1_TV_MODE_OFF ) ){
		up( &par->sem_tvmode );
		return -EIO;
	}
	/* copy fb image info from 2D API */
	if(copy_from_user(&FBSrcnModes, (scrn_modes *) arg, sizeof(scrn_modes))){
		up( &par->sem_tvmode );
		return -EFAULT;
	}

	/* check fb image infomation from 2D API */
	if(chk_input_modes(FBSrcnModes)){
		up( &par->sem_tvmode );
		return -1;
	}

	down(&par->sem_fb_image_info);		/* lock fb_image_info */

	/* set fb image infomation from 2D API */
	set_image_info_from_2DAPI(FBSrcnModes.page, &FBSrcnModes, info);

	/* set fb image infomaition to LCD */
	set_image_info_to_LCD(FBSrcnModes.page, info);

	fb_data[par->devflag].iNextDispPage = FBSrcnModes.page;

	/* when cmd is MP200_FB_SET_MODES, set fb image update flag off */
	if(cmd == MP200_FB_SET_MODES){
		fb_data[par->devflag].fb_image_info.update_flag = FB_UPDATE_OFF;
	}
	/* when cmd is MP200_FB_UPDATE_MODES,  set fb image update flag on */
	else{
		/* absolutely update data */
		if(FBSrcnModes.update == UPDATE_FLAG_ON)
		{
			fb_data[par->devflag].fb_image_info.update_flag = FB_ABSOLUTERY_UPDATE;
		}
		/* when ONLY_2D_MODE, update data */
		else{
			fb_data[par->devflag].fb_image_info.update_flag = FB_UPDATE_ON;
		}
	}

	/* set image infomation to LCD driver */
	printk_dbg((_DEBUG_FB & 0x10), "ioctl(UPDATE_SCRN): request LCD\n");

#ifdef CONFIG_FB_MP200_NTS
	if( par->devflag == EM1_FB_DEVICE_LCD ){
#endif /* CONFIG_FB_MP200_NTS */
		printk_dbg((_DEBUG_FB & 0x02), "toLCD: PaddrYRGB(%lx)\n", fb_data[par->devflag].fb_image_info.image_data.yrgbaddr);
		if(mp200_lcd_set_fb_image(&fb_data[par->devflag].fb_image_info)){
			up(&par->sem_fb_image_info);	/* unlock fb_image_info */
			up( &par->sem_tvmode );
			return -EBUSY;
		}
#ifdef CONFIG_FB_MP200_NTS
	} else {
		printk_dbg((_DEBUG_FB & 0x02), "toNTSC: PaddrYRGB(%lx)\n", fb_data[par->devflag].fb_image_info.image_data.yrgbaddr);
		if(mp200_nts_set_fb_image(&fb_data[par->devflag].fb_image_info)){
			up(&par->sem_fb_image_info);	/* unlock fb_image_info */
			up( &par->sem_tvmode );
			return -EBUSY;
		}
	}
#endif /* CONFIG_FB_MP200_NTS */

	up(&par->sem_fb_image_info);		/* unlock fb_image_info */

	/* PGPF always uses /dev/fb0 as Generic FB */
#ifndef CONFIG_MACH_PGPF
	if (FBSrcnModes.page == DISP_BUFA){
		info->screen_base = (char __iomem *)fb_data[par->devflag].DispBufAV;
	}
	else{
		info->screen_base = (char __iomem *)fb_data[par->devflag].DispBufBV;
	}
#endif /* !CONFIG_PGPF_FB_PND_EXT */

	up( &par->sem_tvmode );

	printk_dbg((_DEBUG_FB & 0x02), "ioctl(UPDATE_SCRN) <end>\n");
	return 0;
}


/******************************************************************************
* MODULE   : mp200_fb_ioc_update_timer
* FUNCTION : frame buffer driver ioctl
* RETURN   :  0      : success
*            -EFAULT :
* NOTE     : none
* CREATE   : 2008.04.03 M.Haguro
* UPDATE   : 2008.12.10 J.Manabe
******************************************************************************/
static int mp200_fb_ioc_update_timer(struct fb_info *info, unsigned long arg)
{
	unsigned long flags;
	update_timer   FbUpdateTimer;
	mp200_fb_par *par = (mp200_fb_par *)info->par;

	printk_dbg((_DEBUG_FB & 0x01), "ioctl(UPDATE_TIMER) <start>\n");

	down( &par->sem_tvmode );
	/* TVMODE Check */
	if( ( par->devflag == EM1_FB_DEVICE_NTS ) && ( tvmode == EM1_TV_MODE_OFF ) ){
		up( &par->sem_tvmode );
		return -EIO;
	}

	/* copy from update timer info from 2D API */
	if(copy_from_user(&FbUpdateTimer, (update_timer *) arg, sizeof(update_timer))){
		up( &par->sem_tvmode );
		return -EFAULT;
	}

	/* fb timer stop */
	spin_lock_irqsave(&fb_data[par->devflag].mp200_fb_dev->fb_lock, flags);
	del_timer(&fb_data[par->devflag].mp200_fb_timer);
	fb_data[par->devflag].iTimerStatusFlag = FB_TIMER_STOP;
	spin_unlock_irqrestore(&fb_data[par->devflag].mp200_fb_dev->fb_lock, flags);

	/* check input value */
	if(chk_input_update_timer(&FbUpdateTimer)){
		up( &par->sem_tvmode );
		return -1;
	}

	/* set update structure info */
	fb_data[par->devflag].iUpdateTimerFlag = FbUpdateTimer.timerflag;
	fb_data[par->devflag].iTimeoutTime     = FbUpdateTimer.timeout;

	/* fb timer start */
	if((fb_data[par->devflag].iUpdateTimerFlag == TIMER_ON) && (fb_data[par->devflag].iMixModeFlg == ONLY_2D_MODE)){
		spin_lock_irqsave(&fb_data[par->devflag].mp200_fb_dev->fb_lock, flags);
		if(fb_data[par->devflag].iTimerStatusFlag == FB_TIMER_STOP){
			printk_dbg((_DEBUG_FB & 0x10), "ioctl(UPDATE_TIMER): add_timer\n");
			fb_data[par->devflag].mp200_fb_timer.expires = jiffies + (fb_data[par->devflag].iTimeoutTime * HZ / 1000);
			add_timer(&fb_data[par->devflag].mp200_fb_timer);
			fb_data[par->devflag].iTimerStatusFlag = FB_TIMER_START;
		}
		spin_unlock_irqrestore(&fb_data[par->devflag].mp200_fb_dev->fb_lock, flags);
	}

	up( &par->sem_tvmode );

	printk_dbg((_DEBUG_FB & 0x02), "ioctl(UPDATE_TIMER) <end>\n");
	return 0;
}
#endif /* !CONFIG_PGPF_FB_UX_EXT */

#ifdef CONFIG_FB_MP200_NTS
/******************************************************************************
* MODULE   : mp200_fb_ioc_set_output
* FUNCTION : frame buffer driver ioctl
* RETURN   :  0      : success
*            -EINVAL : input value error
*            -EIO    : 
* NOTE     : none
* CREATE   : 2009.01.06 J.Manabe
* UPDATE   : 
******************************************************************************/
static int mp200_fb_ioc_set_output(struct fb_info *info, unsigned long arg)
{
	int ret = 0;
	EM1_TV_MODE mode;
	mp200_fb_par *par  = (mp200_fb_par *)info->par;

	printk_dbg((_DEBUG_FB & 0x01), "<start>\n");

	/* fb device check */
	if( par->devflag != EM1_FB_DEVICE_NTS ){
		printk_dbg((_DEBUG_FB & 0x01), "fb1 IF only!\n");
		return -EIO;
	}

	/* copy fb image info from 2D API */
	if( copy_from_user( &mode, ( EM1_TV_MODE * ) arg, sizeof( EM1_TV_MODE ) ) ){
		return -EFAULT;
	}

	down( &par->sem_tvmode );

	/* MODE CHECK */
	if( ( mode != EM1_TV_MODE_OFF ) &&
		( mode != EM1_TV_MODE_NTS ) &&
		( mode != EM1_TV_MODE_PAL )   ){
		up( &par->sem_tvmode );
		return -EINVAL;
	}

	/* ERROR CHECK */
	if( tvmode == mode ){
		up( &par->sem_tvmode );
		return 0;
	} else if( ( tvmode == EM1_TV_MODE_NTS ) && ( mode == EM1_TV_MODE_PAL ) ){
		up( &par->sem_tvmode );
		return -EIO;
	} else if( ( tvmode == EM1_TV_MODE_PAL ) && ( mode == EM1_TV_MODE_NTS ) ){
		up( &par->sem_tvmode );
		return -EIO;
	}

	/* NTS SET */
	if( mode == EM1_TV_MODE_OFF ){
		fb_data[par->devflag].iFBStatus_A = IS_NODATA;
		fb_data[par->devflag].iFBStatus_B = IS_NODATA;

		del_timer( &fb_data[par->devflag].mp200_fb_timer );
		fb_data[par->devflag].iTimerStatusFlag = FB_TIMER_STOP;

		/* NTS SET( OFF ) */
		mp200_nts_release( NTS_ACTIVE_FB );
	} else {
		del_timer( &fb_data[par->devflag].mp200_fb_timer );
		fb_data[par->devflag].iTimerStatusFlag = FB_TIMER_STOP;

		/* NTS SET( NTS/PAL ) */
		ret = mp200_nts_reserve( NTS_ACTIVE_FB, ( int )mode );
		if( ret < 0 ){
			printk_dbg((_DEBUG_FB & 0x01), "nts_reserve err [%d]\n", ret);
			up( &par->sem_tvmode );
			return ret;
		}

		/* Set tv size */
		set_tv_size( mode, par );

		/* timer set */
		if( fb_data[par->devflag].iMixModeFlg == ONLY_2D_MODE ){
			if(fb_data[par->devflag].iUpdateTimerFlag == TIMER_ON){
				printk_dbg((_DEBUG_FB & 0x10), "add_timer()\n");
				add_timer( &fb_data[par->devflag].mp200_fb_timer );	/* start timer interrupt */
				fb_data[par->devflag].iTimerStatusFlag = FB_TIMER_START;
			} else {
				printk_dbg((_DEBUG_FB & 0x10), "queue_work()\n");
				queue_work( par->mp200_fb_workqueue, &par->wk_timeout_update_bottom_half );
			}
		}
	}
	set_tv_var(mode, par);

	/* set output mode */
	tvmode = mode;
	up( &par->sem_tvmode );

	printk_dbg((_DEBUG_FB & 0x01), "< end >\n");
	return 0;
}


/******************************************************************************
* MODULE   : mp200_fb_ioc_get_output
* FUNCTION : frame buffer driver ioctl
* RETURN   :  0      : success
*            -EFAULT :
* NOTE     : none
* CREATE   : 2008.12.25 J.Manabe
* UPDATE   : 
******************************************************************************/
static int mp200_fb_ioc_get_output(struct fb_info *info, unsigned long arg)
{
	EM1_TV_MODE mode;
	mp200_fb_par *par = (mp200_fb_par *)info->par;
	printk_dbg((_DEBUG_FB & 0x01), "<start>\n");

	/* fb device check */
	if( par->devflag != EM1_FB_DEVICE_NTS ){
		printk_dbg((_DEBUG_FB & 0x01), "fb1 IF only!\n");
		return -EIO;
	}

	down( &par->sem_tvmode );
	mode = tvmode;
	/* copy to user EM1_TV_MODE infomation */
	if( copy_to_user( ( EM1_TV_MODE * ) arg, &mode, sizeof( EM1_TV_MODE ) ) ){
		up( &par->sem_tvmode );
		return -EFAULT;
	}
	up( &par->sem_tvmode );

	printk_dbg((_DEBUG_FB & 0x01), "< end >\n");
	return 0;
}
#endif /* CONFIG_FB_MP200_NTS */


#if 0
void ............set_status................(){}
#endif
#ifndef CONFIG_PGPF_FB_UX_EXT
/******************************************************************************
* MODULE   : set_image_info_to_2DAPI
* FUNCTION : set other image infomation (frame bufferA/B) to 2D API
* RETURN   : 0 : success
* NOTE     : none
* CREATE   : 2006.05.26 H.Nagashima
* UPDATE   : 2008.11.14 J.Manabe
******************************************************************************/
static int set_image_info_to_2DAPI(int iFBNo, scrn_modes *fb_scrn_modes, struct fb_info *info)
{
	mp200_fb_par *par = (mp200_fb_par *)info->par;

	/* set fb A other image infomation */
	if(iFBNo == FB_NO_A)
	{
		down(&par->sem_fb_other_info_A);	/* lock fb_other_info_A */
		fb_scrn_modes->tc_enable = fb_data[par->devflag].fb_other_info_A.iMaskColFlg;
		fb_scrn_modes->t_color   = fb_data[par->devflag].fb_other_info_A.iMaskCol;
		fb_scrn_modes->alpha     = fb_data[par->devflag].fb_other_info_A.iAlpha;
		fb_scrn_modes->rot       = fb_data[par->devflag].fb_other_info_A.iInvFlg;
		fb_scrn_modes->page      = fb_data[par->devflag].fb_other_info_A.iPage;
		fb_scrn_modes->update    = fb_data[par->devflag].fb_other_info_A.iUpDate;
		up(&par->sem_fb_other_info_A);		/* unlock fb_other_info_A */
	}
	/* set fb B other image infomation */
	else
	{
		down(&par->sem_fb_other_info_B);	/* lock fb_other_info_B */
		fb_scrn_modes->tc_enable = fb_data[par->devflag].fb_other_info_B.iMaskColFlg;
		fb_scrn_modes->t_color   = fb_data[par->devflag].fb_other_info_B.iMaskCol;
		fb_scrn_modes->alpha     = fb_data[par->devflag].fb_other_info_B.iAlpha;
		fb_scrn_modes->rot       = fb_data[par->devflag].fb_other_info_B.iInvFlg;
		fb_scrn_modes->page      = fb_data[par->devflag].fb_other_info_B.iPage;
		fb_scrn_modes->update    = fb_data[par->devflag].fb_other_info_B.iUpDate;
		up(&par->sem_fb_other_info_B);		/* unlock fb_other_info_B */
	}
	return 0;
}


/******************************************************************************
* MODULE   : chk_fb_status
* FUNCTION : check frame buffer (A/B) status
* RETURN   : 0 : update enable
*            1 : update disable
* NOTE     : none
* CREATE   : 2006.05.26 H.Nagashima
* UPDATE   : 2008.11.14 J.Manabe
******************************************************************************/
static int chk_fb_status(int iFBStatus)
{
	int iRet;

	/* check frame buffer status */
	if(iFBStatus == IS_NODATA || iFBStatus == ENABLE_WRITE)
	{
		iRet = OUT_OF_DISPLAY;
	}
	else
	{
		iRet = WAITING_FOR_ON_DISPLAY;
	}
	return iRet;
}


/******************************************************************************
* MODULE   : chk_input_modes
* FUNCTION : check input scrn_modes value from 2D API
* RETURN   : 0       : correct
*            -EINVAL : incorrect
* NOTE     : none
* CREATE   : 2006.06.05 H.Nagashima
* UPDATE   :
******************************************************************************/
static int chk_input_modes(scrn_modes fb_scrn_modes)
{
	/* check mask color flag */
	if((fb_scrn_modes.tc_enable != FB_MASK_COLOR_DISP_OFF) && (fb_scrn_modes.tc_enable != FB_MASK_COLOR_DISP_ON))
	{
		printk_wrn("mask color flag incorrect  tc_enable = %d\n", fb_scrn_modes.tc_enable);
		return -EINVAL;
	}

	/* check mask color */
	if((fb_scrn_modes.t_color < 0x00) || (0xFFFF < fb_scrn_modes.t_color))
	{
		printk_wrn("mask color incorrect  t_color = %d\n", fb_scrn_modes.t_color);
		return -EINVAL;
	}

	/* check alpha */
	if((fb_scrn_modes.alpha < 0x00) || (0xFF < fb_scrn_modes.alpha))
	{
		printk_wrn("alpha incorrect  alpha = %d\n", fb_scrn_modes.alpha);
		return -EINVAL;
	}

	/* check rot */
	if((fb_scrn_modes.rot != NO_INVERSE) && (fb_scrn_modes.rot != UDRL_INVERSE))
	{
		printk_wrn("rot incorrect  rot = %d\n", fb_scrn_modes.rot);
		return -EINVAL;
	}

	/* check page */
	if((fb_scrn_modes.page != FB_NO_A) && (fb_scrn_modes.page != FB_NO_B))
	{
		printk_wrn("page incorrect  page = %d\n", fb_scrn_modes.page);
		return -EINVAL;
	}

	/* check update */
	if((fb_scrn_modes.update != UPDATE_FLAG_OFF) && (fb_scrn_modes.update != UPDATE_FLAG_ON))
	{
		printk_wrn("update incorrect  update = %d\n", fb_scrn_modes.update);
		return -EINVAL;
	}

	return 0;
}


/******************************************************************************
* MODULE   : set_image_info_from_2DAPI
* FUNCTION : set image infomation from LCD to fb local
* RETURN   : 0 : success
* NOTE     : none
* CREATE   : 2006.05.26 H.Nagashima
* UPDATE   :
******************************************************************************/
static int set_image_info_from_2DAPI(int iFBNo, scrn_modes *fb_scrn_modes, struct fb_info *info)
{
	mp200_fb_par *par = (mp200_fb_par *)info->par;

	/* set FB_A image infomation from 2D API */
	if(iFBNo == FB_NO_A)
	{
		fb_data[par->devflag].iFBStatus_A = NOW_WRITING_TO_FB;

		down(&par->sem_fb_other_info_A);	/* lock fb_other_info_A */
		fb_data[par->devflag].fb_other_info_A.iMaskColFlg = fb_scrn_modes->tc_enable;
		fb_data[par->devflag].fb_other_info_A.iMaskCol    = fb_scrn_modes->t_color;
		fb_data[par->devflag].fb_other_info_A.iAlpha      = fb_scrn_modes->alpha;
		fb_data[par->devflag].fb_other_info_A.iInvFlg     = fb_scrn_modes->rot;
		fb_data[par->devflag].fb_other_info_A.iPage       = fb_scrn_modes->page;
		fb_data[par->devflag].fb_other_info_A.iUpDate     = fb_scrn_modes->update;
		up(&par->sem_fb_other_info_A);		/* unlock fb_other_info_A */
	}
	/* set FB_B image infomation from 2D API */
	else
	{
		fb_data[par->devflag].iFBStatus_B = NOW_WRITING_TO_FB;

		down(&par->sem_fb_other_info_B);	/* lock fb_other_info_B */
		fb_data[par->devflag].fb_other_info_B.iMaskColFlg = fb_scrn_modes->tc_enable;
		fb_data[par->devflag].fb_other_info_B.iMaskCol    = fb_scrn_modes->t_color;
		fb_data[par->devflag].fb_other_info_B.iAlpha      = fb_scrn_modes->alpha;
		fb_data[par->devflag].fb_other_info_B.iInvFlg     = fb_scrn_modes->rot;
		fb_data[par->devflag].fb_other_info_B.iPage       = fb_scrn_modes->page;
		fb_data[par->devflag].fb_other_info_B.iUpDate     = fb_scrn_modes->update;
		up(&par->sem_fb_other_info_B);		/* unlock fb_other_info_B */
	}
	printk_dbg((_DEBUG_FB & 0x08), "[> set_2DAPI:   A(%d) B(%d)\n", fb_data[par->devflag].iFBStatus_A, fb_data[par->devflag].iFBStatus_B);

	return 0;
}


/******************************************************************************
* MODULE   : set_image_info_to_LCD
* FUNCTION : set image infomation to LCD
* RETURN   : 0 : success
* NOTE     : none
* CREATE   : 2006.05.26 H.Nagashima
* UPDATE   : 2008.11.14 J.Manabe
******************************************************************************/
static int set_image_info_to_LCD(int iFBNo, struct fb_info *info)
{
	mp200_fb_par *par = (mp200_fb_par *)info->par;

	/* set fb A infomation */
	if(iFBNo == DISP_BUFA)
	{
		printk_dbg((_DEBUG_FB & 0x04), "DispBufA(%08lx)\n", fb_data[par->devflag].DispBufA);
		fb_data[par->devflag].fb_image_info.image_data.yrgbaddr = fb_data[par->devflag].DispBufA;

		/* set other image infomation */
		down(&par->sem_fb_other_info_A);	/* lock fb_other_info_A */
		fb_data[par->devflag].fb_image_info.maskcolr     = fb_data[par->devflag].fb_other_info_A.iMaskCol;
		fb_data[par->devflag].fb_image_info.maskcolrflg  = fb_data[par->devflag].fb_other_info_A.iMaskColFlg;
		fb_data[par->devflag].fb_image_info.alpha        = fb_data[par->devflag].fb_other_info_A.iAlpha;
		fb_data[par->devflag].fb_image_info.invflg       = fb_data[par->devflag].fb_other_info_A.iInvFlg;
		fb_data[par->devflag].fb_image_info.mix_buf_page = fb_data[par->devflag].fb_other_info_A.iPage;
		up(&par->sem_fb_other_info_A);		/* unlock fb_other_info_A */
	}
	/* set fb B infomation */
	else
	{
		printk_dbg((_DEBUG_FB & 0x04), "DispBufB(%08lx)\n", fb_data[par->devflag].DispBufB);
		fb_data[par->devflag].fb_image_info.image_data.yrgbaddr = fb_data[par->devflag].DispBufB;

		/* set other image infomation */
		down(&par->sem_fb_other_info_B);	/* lock fb_other_info_B */
		fb_data[par->devflag].fb_image_info.maskcolr     = fb_data[par->devflag].fb_other_info_B.iMaskCol;
		fb_data[par->devflag].fb_image_info.maskcolrflg  = fb_data[par->devflag].fb_other_info_B.iMaskColFlg;
		fb_data[par->devflag].fb_image_info.alpha        = fb_data[par->devflag].fb_other_info_B.iAlpha;
		fb_data[par->devflag].fb_image_info.invflg       = fb_data[par->devflag].fb_other_info_B.iInvFlg;
		fb_data[par->devflag].fb_image_info.mix_buf_page = fb_data[par->devflag].fb_other_info_B.iPage;
		up(&par->sem_fb_other_info_B);		/* unlock fb_other_info_B */
	}

	return 0;
}


/******************************************************************************
* MODULE   : chk_input_update_timer
* FUNCTION : check update timer value from 2D API
* RETURN   : 0       : success
           : -EINVAL : input value error
* NOTE     : none
* CREATE   : 2006.05.26 H.Nagashima
* UPDATE   :
******************************************************************************/
static int chk_input_update_timer(update_timer *fb_timer)
{
	/* check update mode value */
	if((fb_timer->timerflag != TIMER_OFF) && (fb_timer->timerflag != TIMER_ON))
	{
		printk_wrn("timerflag value incorrect  timerflag = %d\n", fb_timer->timerflag);
		return -EINVAL;
	}

	/* check update mode value */
	if(fb_timer->timeout < 33)
	{
		printk_wrn("timeout value incorrect  timeout = %d\n", fb_timer->timeout);
		return -EINVAL;
	}

	return 0;
}
#endif /* !CONFIG_PGPF_FB_UX_EXT */

#ifdef CONFIG_FB_MP200_NTS
/******************************************************************************
* MODULE   : set_tv_size
* FUNCTION : tvmode change
* RETURN   : 0 : success
* NOTE     : none
* CREATE   : 2008.12.04 J.Manabe
* UPDATE   : 
******************************************************************************/
static void set_tv_size( EM1_TV_MODE mode, mp200_fb_par *par )
{
	printk_dbg((_DEBUG_FB & 0x01), "<start>\n");

	down( &par->sem_fb_image_info );

	switch( mode ){
	case EM1_TV_MODE_NTS:
		fb_data[par->devflag].fb_image_info.image_data.hsize    = NTSC_WIDTH;
		fb_data[par->devflag].fb_image_info.image_data.vsize    = NTSC_HEIGHT;
		fb_data[par->devflag].fb_image_info.image_data.size     = NTSC_WIDTH * BYTES_PER_PIXEL;
		break;
	case EM1_TV_MODE_PAL:
		fb_data[par->devflag].fb_image_info.image_data.hsize    = PAL_WIDTH;
		fb_data[par->devflag].fb_image_info.image_data.vsize    = PAL_HEIGHT;
		fb_data[par->devflag].fb_image_info.image_data.size     = PAL_WIDTH * BYTES_PER_PIXEL;
		break;
	default :
	/* EM1_TV_MODE_OFF */
	break;
	}

	up( &par->sem_fb_image_info );

	printk_dbg((_DEBUG_FB & 0x01), "< end >\n");
}


/******************************************************************************
* MODULE   : set_tv_var
* FUNCTION : tvmode change
* RETURN   : 0 : success
* NOTE     : none
* CREATE   : 2009.1.19 M.haguro
* UPDATE   : 
******************************************************************************/
static void set_tv_var( EM1_TV_MODE mode, mp200_fb_par *par )
{
	printk_dbg((_DEBUG_FB & 0x01), "<start>\n");

	down( &par->sem_fb_image_info );

	switch( mode ){
	case EM1_TV_MODE_NTS:
		par->fb_inf->var = mp200_fb_tv_default;
		par->fb_inf->var.xres         = NTSC_WIDTH;
		par->fb_inf->var.yres         = NTSC_HEIGHT;
		par->fb_inf->var.xres_virtual = NTS_WIDTH_V;
		par->fb_inf->var.yres_virtual = NTS_HEIGHT_V;
		par->fb_inf->var.bits_per_pixel = 16;
		break;
	case EM1_TV_MODE_PAL:
		par->fb_inf->var = mp200_fb_tv_default;
		par->fb_inf->var.xres         = PAL_WIDTH;
		par->fb_inf->var.yres         = PAL_HEIGHT;
		par->fb_inf->var.xres_virtual = NTS_WIDTH_V;
		par->fb_inf->var.yres_virtual = NTS_HEIGHT_V;
		par->fb_inf->var.bits_per_pixel = 16;
		break;
	default :
		/* EM1_TV_MODE_OFF */
		goto failed;
	}
	mp200_fb_set_par(par->fb_inf);

failed:
	up( &par->sem_fb_image_info );

	printk_dbg((_DEBUG_FB & 0x01), "< end >\n");
}
#endif /* CONFIG_FB_MP200_NTS */



#if 0
void ............fb_ops................(){}
#endif
/******************************************************************************
* MODULE   : mp200_fb_mmap
* FUNCTION : mmap
* RETURN   : 0       : success
*          : -EINVAL : input value error
*          : -EAGAIN : run again
* NOTE     : none
* CREATE   :
* UPDATE   : 2006.11.16 H.Nagashima
* UPDATE   : 2008.11.27 J.Manabe
******************************************************************************/
int mp200_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
{
	unsigned long start;
	unsigned long off;
	u32 len;

	if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
	{
		return -EINVAL;
	}

	off = vma->vm_pgoff << PAGE_SHIFT;
	if (off < DispBufAllLength)
	{
		start = (unsigned long)Smem;
		len = PAGE_ALIGN((start & ~PAGE_MASK) + DispBufAllLength);
	}
	else
	{
		return -EINVAL;
	}

	start &= PAGE_MASK;
	if ((vma->vm_end - vma->vm_start + off) > len)
	{
		return -EINVAL;
	}

	off += start;
	vma->vm_pgoff = off >> PAGE_SHIFT;

	/* Accessing memory will be done non-cached. */
	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) | L_PTE_BUFFERABLE);
	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) & ~L_PTE_CACHEABLE);

	/* To stop the swapper from even considering these pages */
	vma->vm_flags |= (VM_IO | VM_RESERVED);

	if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, vma->vm_end - vma->vm_start, vma->vm_page_prot))
	{
		return -EAGAIN;
	}

	return 0;
}


/******************************************************************************
* MODULE   : mp200_fb_open
* FUNCTION : open qfb driver
* RETURN   : 0      : success
*            -EBUSY : LCD initialize failed
* NOTE     : none
* CREATE   :
* UPDATE   : 2006.05.29 H.Nagashima
* UPDATE   : 2008.11.14 J.Manabe
******************************************************************************/
static int mp200_fb_open(struct fb_info *info, int user)
{
	mp200_fb_par *par      = (mp200_fb_par *)info->par;

	if(fb_data[par->devflag].is_first){
		if( par->devflag == EM1_FB_DEVICE_LCD ){
			/* initialize LCD driver */
#ifdef CONFIG_PGPF_LCD
			pgpf_lcdhw_init();
#else /* CONFIG_PGPF_LCD */
			if (init_lcdhw() != 0){
				printk_wrn("initialize LCD failed.\n");
				return -EBUSY;
			}
#endif /* CONFIG_MACH_PGPF */
			printk_dbg((_DEBUG_FB & 0x10), "queue_work\n");
			queue_work(par->mp200_fb_workqueue, &par->wk_timeout_update_bottom_half);
		}
		timer_init(info);
		fb_data[par->devflag].is_first = 0;
#ifdef CONFIG_MACH_PGPF
		{
			int ret;
			down(&par->sem_fb_image_info);
#ifdef CONFIG_PGPF_FB_PND_EXT
#ifdef CONFIG_PGPF_FB_LAYER2
			ret = mp200_fb_set_image(&fb_data[par->devflag].fb_image_info, &fb_data[par->devflag].bg_image_info, &fb_data[par->devflag].l2_image_info, &fb_data[par->devflag].console_image_info, par->devflag);
#else /* CONFIG_PGPF_FB_LAYER2 */
			ret = mp200_fb_set_image(&fb_data[par->devflag].fb_image_info, &fb_data[par->devflag].bg_image_info, NULL, &fb_data[par->devflag].console_image_info, par->devflag);
#endif /* CONFIG_PGPF_FB_LAYER2 */
#else /* CONFIG_PGPF_FB_PND_EXT */
#ifdef CONFIG_PGPF_FB_LAYER2
			ret = mp200_fb_set_image(&fb_data[par->devflag].fb_image_info, NULL, &fb_data[par->devflag].l2_image_info, NULL, par->devflag);
#else /* CONFIG_PGPF_FB_LAYER2 */
			ret = mp200_fb_set_image(&fb_data[par->devflag].fb_image_info, NULL, NULL, NULL, NULL, par->devflag);
#endif /* CONFIG_PGPF_FB_LAYER2 */
#endif /* CONFIG_PGPF_FB_PND_EXT */
			up(&par->sem_fb_image_info);
			if (ret) {
				return ret;
			}
		}
#endif /* CONFIG_MACH_PGPF */
	}

	atomic_inc(&par->use_count);

	return 0;
}


/******************************************************************************
* MODULE   : mp200_fb_release
* FUNCTION : close qfb driver
* RETURN   : 0       : success
*            -EINVAL : 
* NOTE     : none
* CREATE   :
* UPDATE   : 2006.05.29 H.Nagashima
* UPDATE   : 2009.01.06 J.Manabe
******************************************************************************/
static int mp200_fb_release(struct fb_info *info, int user)
{
	mp200_fb_par *par = (mp200_fb_par *)info->par;
	u32           count;
	unsigned long flags;

	down( &par->sem_tvmode );

	down(&par->sem_fb_image_info);		/* lock fb_image_info */
	count = atomic_read(&par->use_count);
	if (count == 0)
	{
		up(&par->sem_fb_image_info);		/* unlock fb_image_info */
		up( &par->sem_tvmode );
		return -EINVAL;
	}

	if (count == 1) {
		if( par->devflag == EM1_FB_DEVICE_LCD ){
			/* keep timer status for NAVU */
			fb_data[par->devflag].iUpdateTimerFlag = DEFALT_UPDATE_TIMER_LCD;
			fb_data[par->devflag].iTimeoutTime     = TIMEOUT_TIME;
			del_timer(&fb_data[par->devflag].mp200_fb_timer);
 			fb_data[par->devflag].iTimerStatusFlag = FB_TIMER_STOP;
 			if((fb_data[par->devflag].iUpdateTimerFlag == TIMER_ON) && 
			   (fb_data[par->devflag].iMixModeFlg == ONLY_2D_MODE))
			{
				fb_data[par->devflag].mp200_fb_timer.expires = jiffies + (fb_data[par->devflag].iTimeoutTime * HZ / 1000);
				add_timer(&fb_data[par->devflag].mp200_fb_timer);
				fb_data[par->devflag].iTimerStatusFlag = FB_TIMER_START;
			}
		} else {
			spin_lock_irqsave(&fb_data[par->devflag].mp200_fb_dev->fb_lock, flags);
			/* default timer on */
			fb_data[par->devflag].iUpdateTimerFlag = TIMER_ON;
			fb_data[par->devflag].iTimeoutTime     = TIMEOUT_TIME;
			del_timer(&fb_data[par->devflag].mp200_fb_timer);
			fb_data[par->devflag].iTimerStatusFlag = FB_TIMER_STOP;
			spin_unlock_irqrestore(&fb_data[par->devflag].mp200_fb_dev->fb_lock, flags);

#ifdef CONFIG_FB_MP200_NTS
			/* NTS SET( OFF ) */
			mp200_nts_release( NTS_ACTIVE_FB );
#endif /* CONFIG_FB_MP200_NTS */
			tvmode = EM1_TV_MODE_OFF;
			
			fb_data[par->devflag].iFBStatus_A = IS_NODATA;
			fb_data[par->devflag].iFBStatus_B = IS_NODATA;
		}
	}

	atomic_dec(&par->use_count);
	up(&par->sem_fb_image_info);		/* unlock fb_image_info */
	up( &par->sem_tvmode );
	return 0;
}


/******************************************************************************
* MODULE   : get_line_length
* FUNCTION : get line length
* RETURN   : length
* NOTE     : none
* CREATE   :
* UPDATE   :
******************************************************************************/
static u_long get_line_length(int xres_virtual, int bpp)
{
	u_long length;

	length = xres_virtual * bpp;
	length = (length + 31) & ~31;
	length >>= 3;
	return length;
}


/******************************************************************************
* MODULE   : mp200_fb_check_var
* FUNCTION : variable check
* RETURN   : 0       : success
*            -EINVAL : input value incorrect
*            -ENOMEM :
* NOTE     : none
* CREATE   :
* UPDATE   : 2006.05.29 H.Nagashima
* UPDATE   : 2008.11.14 J.Manabe
******************************************************************************/
static int mp200_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
	u_long line_length;
#ifndef CONFIG_PGPF_FB_UX_EXT
	mp200_fb_par *par  = (mp200_fb_par *)info->par;
#endif /* !CONFIG_PGPF_FB_UX_EXT */

	if (var->vmode & FB_VMODE_CONUPDATE)
	{
		var->vmode |= FB_VMODE_YWRAP;
		var->xoffset = info->var.xoffset;
		var->yoffset = info->var.yoffset;
	}

	/* Some very basic checks */
	if (!var->xres)                     var->xres = 1;
	if (!var->yres)                     var->yres = 1;
	if (var->xres > var->xres_virtual)  var->xres_virtual = var->xres;
	if (var->yres > var->yres_virtual)  var->yres_virtual = var->yres;
	if (var->bits_per_pixel <= 1)       var->bits_per_pixel = 1;
	else if (var->bits_per_pixel <= 8)  var->bits_per_pixel = 8;
	else if (var->bits_per_pixel <= 16) var->bits_per_pixel = 16;
	else if (var->bits_per_pixel <= 24) var->bits_per_pixel = 24;
	else if (var->bits_per_pixel <= 32) var->bits_per_pixel = 32;
	else                                return -EINVAL;

	if (var->xres_virtual < var->xoffset + var->xres)
	{
		var->xres_virtual = var->xoffset + var->xres;
	}
	if (var->yres_virtual < var->yoffset + var->yres)
	{
		var->yres_virtual = var->yoffset + var->yres;
	}

	/* Memory limit */
	line_length = get_line_length(var->xres_virtual, var->bits_per_pixel);
#ifdef CONFIG_PGPF_FB_UX_EXT
	if (line_length * var->yres_virtual > SmemLength)
	{
		return -ENOMEM;
	}
#else /* CONFIG_PGPF_FB_UX_EXT */
	if (line_length * var->yres_virtual > fb_data[par->devflag].DispBufLength)
	{
		return -ENOMEM;
	}
#endif /* CONFIG_PGPF_FB_UX_EXT */

	/* check var */
	switch (var->bits_per_pixel)
	{
		case 1:	/* FALL THROUGH */
		case 8:
		{
			var->red.offset    = 0;
			var->red.length    = 8;
			var->green.offset  = 0;
			var->green.length  = 8;
			var->blue.offset   = 0;
			var->blue.length   = 8;
			var->transp.offset = 0;
			var->transp.length = 0;
			break;
		}
		case 16:		/* RGBA 5551 */
		{
			if (var->transp.length)
			{
				var->red.offset    = 0;
				var->red.length    = 5;
				var->green.offset  = 5;
				var->green.length  = 5;
				var->blue.offset   = 10;
				var->blue.length   = 5;
				var->transp.offset = 15;
				var->transp.length = 1;
			}
			else		/* RGB 565 */
			{
				var->red.offset    = 11;
				var->red.length    = 5;
				var->green.offset  = 5;
				var->green.length  = 6;
				var->blue.offset   = 0;
				var->blue.length   = 5;
				var->transp.offset = 0;
				var->transp.length = 0;
			}
			break;
		}
		case 24:		/* RGB 888 */
		{
			var->red.offset    = 0;
			var->red.length    = 8;
			var->green.offset  = 8;
			var->green.length  = 8;
			var->blue.offset   = 16;
			var->blue.length   = 8;
			var->transp.offset = 0;
			var->transp.length = 0;
			break;
		}
		case 32:		/* RGBA 8888 */
		{
			var->red.offset    = 0;
			var->red.length    = 8;
			var->green.offset  = 8;
			var->green.length  = 8;
			var->blue.offset   = 16;
			var->blue.length   = 8;
			var->transp.offset = 24;
			var->transp.length = 8;
			break;
		}
	}
	var->red.msb_right    = 0;
	var->green.msb_right  = 0;
	var->blue.msb_right   = 0;
	var->transp.msb_right = 0;

	return 0;
}

/******************************************************************************
* MODULE   : mp200_fb_set_par
* FUNCTION : set qfb parameter
* RETURN   : 0 : success
* NOTE     : none
* CREATE   :
* UPDATE   : 2006.05.29 H.Nagashima
******************************************************************************/
static int mp200_fb_set_par(struct fb_info *info)
{
	info->fix.line_length = get_line_length(info->var.xres_virtual, info->var.bits_per_pixel);
	return 0;
}


/******************************************************************************
* MODULE   : mp200_fb_setcolreg
* FUNCTION : set qfb color
* RETURN   : 0 : success
*            1 :
* NOTE     : none
* CREATE   :
* UPDATE   : 2006.05.29 H.Nagashima
******************************************************************************/
static int mp200_fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info *info)
{
	/* No. of hw registers */
	if (regno >= 256)
		return 1;

	/* grayscale works only partially under directcolor */
	if (info->var.grayscale)
	{
		/* grayscale = 0.30*R + 0.59*G + 0.11*B */
		red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
	}

#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
	switch (info->fix.visual)
	{
		case FB_VISUAL_TRUECOLOR:	/* FALL THROUGH */
		case FB_VISUAL_PSEUDOCOLOR:
		{
			red = CNVT_TOHW(red, info->var.red.length);
			green = CNVT_TOHW(green, info->var.green.length);
			blue = CNVT_TOHW(blue, info->var.blue.length);
			transp = CNVT_TOHW(transp, info->var.transp.length);
			break;
		}
		case FB_VISUAL_DIRECTCOLOR:
		{
			red = CNVT_TOHW(red, 8);	/* expect 8 bit DAC */
			green = CNVT_TOHW(green, 8);
			blue = CNVT_TOHW(blue, 8);
			/* hey, there is bug in transp handling... */
			transp = CNVT_TOHW(transp, 8);
			break;
		}
	}
#undef CNVT_TOHW
	/* Truecolor has hardware independent palette */
	if (info->fix.visual == FB_VISUAL_TRUECOLOR)
	{
		u32 v;

		if (regno >= 16)
		{
			return 1;
		}

		v = (red << info->var.red.offset)   | (green << info->var.green.offset)  |
		    (blue << info->var.blue.offset) | (transp << info->var.transp.offset);
		switch (info->var.bits_per_pixel)
		{
			case 16:	/* FALL THROUGH */
			case 24:	/* FALL THROUGH */
			case 32:
			{
				((u32 *) (info->pseudo_palette))[regno] = v;
				break;
			}
			case 8:		/* FALL THROUGH */
			default :
			{
				break;
			}
		}
	}
	return 0;
}

/******************************************************************************
* MODULE   : mp200_fb_pan_display
* FUNCTION :
* RETURN   : 0       : success
*            -EINVAL : input value incorrect
* NOTE     : none
* CREATE   :
* UPDATE   : 2006.05.29 H.Nagashima
******************************************************************************/
static int mp200_fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
{
#ifdef CONFIG_PGPF_FB_UX_EXT
	mp200_fb_par *par = (mp200_fb_par *)info->par;
#endif /* CONFIG_PGPF_FB_UX_EXT */
	if (var->vmode & FB_VMODE_YWRAP)
	{
		if (var->yoffset < 0 || var->yoffset >= info->var.yres_virtual || var->xoffset)
		{
			return -EINVAL;
		}
	}
	else
	{
		if (var->xoffset + var->xres > info->var.xres_virtual ||
		    var->yoffset + var->yres > info->var.yres_virtual )
		{
			return -EINVAL;
		}
	}
	info->var.xoffset = var->xoffset;
	info->var.yoffset = var->yoffset;
	if (var->vmode & FB_VMODE_YWRAP)
	{
		info->var.vmode |= FB_VMODE_YWRAP;
	}
	else
	{
		info->var.vmode &= ~FB_VMODE_YWRAP;
	}

#ifdef CONFIG_PGPF_FB_UX_EXT 
	fb_data[par->devflag].fb_image_info.image_data.yrgbaddr = fb_data[par->devflag].DispBufA;
	fb_data[par->devflag].fb_image_info.image_data.x = var->xoffset;
	fb_data[par->devflag].fb_image_info.image_data.y = var->yoffset;
	mp200_fb_wait_vsync(info, 0);
	if (down_interruptible(&par->sem_fb_image_info)) { 
		return -EBUSY;
	} 
	if (fb_data[par->devflag].iUpdateTimerFlag == TIMER_OFF) { 
		fb_data[par->devflag].fb_image_info.update_flag = FB_ABSOLUTERY_UPDATE; 
		mp200_lcd_set_fb_image(&fb_data[par->devflag].fb_image_info); 
	} 
	up(&par->sem_fb_image_info); 
#endif 

	return 0;
}


/******************************************************************************
* MODULE   : mp200_fb_callback
* FUNCTION : call back from LCD driver
* RETURN   : none
* NOTE     : public function
* CREATE   : 2006.05.27 H.Nagashima
* UPDATE   : 2008.11.14 J.Manabe
******************************************************************************/
void mp200_fb_callback(int iWrittenFBNo, int iMixModeStatus, int fb_num)
{
	printk_dbg((_DEBUG_FB & 0x01), "fb(%d) status(%d) from(%d)\n", iWrittenFBNo, iMixModeStatus, fb_num);
	fb_data[fb_num].iMixModeFlg = iMixModeStatus;

#if defined(CONFIG_PGPF_FB_PND_EXT) || defined(CONFIG_PGPF_FB_UX_EXT)
	if (vsync_flag == 0) {
		vsync_flag = 1;
		wake_up_interruptible(&mp200_vsync_wq);
	}
#endif /* CONFIG_PGPF_FB_*_EXT */
#ifdef CONFIG_PGPF_FB_PND_EXT
	if (mp200_auto_scroll_is_active(fb_num)) {
		mp200_fb_par* par = (mp200_fb_par*)fb_data[fb_num].mp200_fb_dev->fb_inf->par;
		queue_work(par->auto_scroll_workqueue, &par->wk_auto_scroll);
	}
#endif /* CONFIG_PGPF_FB_PND_EXT */

	/* fb timer stop */
	del_timer(&fb_data[fb_num].mp200_fb_timer);
	fb_data[fb_num].iTimerStatusFlag = FB_TIMER_STOP;

	/* change FB (A/B) status */
	if(iWrittenFBNo == FB_NO_A)
	{
		fb_data[fb_num].iNowDispPage = FB_NO_A;
		fb_data[fb_num].iFBStatus_A  = ALREADY_DISPLAY;
		if (fb_data[fb_num].iNextDispPage != FB_NO_B){
			fb_data[fb_num].iFBStatus_B = ENABLE_WRITE;
#if (TIMEOUT_MSLEEP==0)
			wake_up_interruptible(&fb_data[fb_num].mp200_fb_dev->wait_fb_chk_scrn);
#endif
		}
	}
	else
	{
		fb_data[fb_num].iNowDispPage = FB_NO_B;
		fb_data[fb_num].iFBStatus_B  = ALREADY_DISPLAY;
		if (fb_data[fb_num].iNextDispPage != FB_NO_A){
			fb_data[fb_num].iFBStatus_A = ENABLE_WRITE;
#if (TIMEOUT_MSLEEP==0)
			wake_up_interruptible(&fb_data[fb_num].mp200_fb_dev->wait_fb_chk_scrn);
#endif
		}
	}
	printk_dbg((_DEBUG_FB & 0x08), "<] callback:    A(%d) B(%d)\n", fb_data[fb_num].iFBStatus_A, fb_data[fb_num].iFBStatus_B);

	/* start timer */
	if((fb_data[fb_num].iUpdateTimerFlag == TIMER_ON) && (fb_data[fb_num].iMixModeFlg == ONLY_2D_MODE)
#if defined(CONFIG_PM) || defined(CONFIG_DPM)
	    && !fb_data[fb_num].iDpmSuspendFlag
#endif /* CONFIG_PM || CONFIG_DPM */
	){
		printk_dbg((_DEBUG_FB & 0x10), "resume: callback: add_timer\n");
		fb_data[fb_num].mp200_fb_timer.expires = jiffies + (fb_data[fb_num].iTimeoutTime * HZ / 1000);
		add_timer(&fb_data[fb_num].mp200_fb_timer);
		fb_data[fb_num].iTimerStatusFlag = FB_TIMER_START;
	}
}


#if 0
void ............Init_Function................(){}
#endif
/********************************************************
 *  Init Function Definitions                           *
 *******************************************************/
/******************************************************************************
* MODULE   : mp200_fb_init_module
* FUNCTION : frame buffer driver init function
* RETURN   : 0      : success
*            -ENXIO : fail
* NOTE     : none
* CREATE   :
* UPDATE   : 2006.05.27 H.Nagashima
******************************************************************************/
int __init mp200_fb_init_module(void)
{
	int   iRet   = 0;

	iRet = platform_driver_register(&mp200_fb_driver);
	if (!iRet)
	{
		return iRet;
	}
	return 0;
}


/******************************************************************************
* MODULE   : mp200_fb_probe
* FUNCTION : frame buffer driver probe function
* RETURN   : 0       : success
*            -ENOMEM : mem error
*            -EBUSY  : other driver init error
* NOTE     : none
* CREATE   :
* UPDATE   : 2006.05.27 H.Nagashima
* UPDATE   : 2008.12.04 J.Manabe
******************************************************************************/
static int __init mp200_fb_probe(struct platform_device *dev)
{
	struct fb_info         *info = NULL;
	struct fb_info         *info_0 = NULL;
	struct fb_info         *info_1 = NULL;
	mp200_fb_par           *par  = NULL;
	int                     iRet = -ENOMEM;
	int                     fb_num = 0;

	printk_info("FB Address List: \n"
				"Generic FB Address:\t0x%08x, Size: 0x%08x(%u)\n"
#ifdef CONFIG_PGPF_FB_PND_EXT
				"GUI1 Address:\t0x%08x, Size: 0x%08x(%u)\n"
				"GUI2 Address:\t0x%08x, Size: 0x%08x(%u)\n"
				"BG1 Address:\t0x%08x, Size: 0x%08x(%u)\n"
				"BG2 Address:\t0x%08x, Size: 0x%08x(%u)\n"
#endif /* CONFIG_PGPF_FB_PND_EXT */
#ifdef CONFIG_PGPF_FB_LAYER2
				"Sub1 Address:\t0x%08x, Size: 0x%08x(%u)\n"
				"Sub2 Address:\t0x%08x, Size: 0x%08x(%u)\n"
#endif /* CONFIG_PGPF_FB_LAYER2 */
#ifdef CONFIG_VIDEO_MP200
				"ROT Shared Address:\t0x%08x, Size: 0x%08x(%u)\n"
				"IMG Shared Address:\t0x%08x, Size: 0x%08x(%u)\n"
#endif /* CONFIG_VIDEO_MP200 */
				, (unsigned int)FB_FRAME_BUFFER_ADDR, (unsigned int)FB_FRAME_BUFFER_SIZE, (unsigned int)FB_FRAME_BUFFER_SIZE
#ifdef CONFIG_PGPF_FB_PND_EXT
				, (unsigned int)(FB_FRAME_BUFFER_ADDR + DISPBUF_A_OFFSET), (unsigned int)DISPBUF_LENGTH, (unsigned int)DISPBUF_LENGTH
				, (unsigned int)(FB_FRAME_BUFFER_ADDR + DISPBUF_B_OFFSET), (unsigned int)DISPBUF_LENGTH, (unsigned int)DISPBUF_LENGTH
				, (unsigned int)(FB_FRAME_BUFFER_ADDR + BASE_A_OFFSET), (unsigned int)BASEBUF_LENGTH, (unsigned int)BASEBUF_LENGTH
				, (unsigned int)(FB_FRAME_BUFFER_ADDR + BASE_B_OFFSET), (unsigned int)BASEBUF_LENGTH, (unsigned int)BASEBUF_LENGTH
#endif /* CONFIG_PGPF_FB_PND_EXT */
#ifdef CONFIG_PGPF_FB_LAYER2
				, (unsigned int)(FB_FRAME_BUFFER_ADDR + SUB_A_OFFSET), (unsigned int)SUBBUF_LENGTH, (unsigned int)SUBBUF_LENGTH
				, (unsigned int)(FB_FRAME_BUFFER_ADDR + SUB_B_OFFSET), (unsigned int)SUBBUF_LENGTH, (unsigned int)SUBBUF_LENGTH
#endif /* CONFIG_PGPF_FB_LAYER2 */
#ifdef CONFIG_VIDEO_MP200
				, (unsigned int)ROT_SHARED_ADDR, (unsigned int)ROT_SHARED_SIZE, (unsigned int)ROT_SHARED_SIZE
				, (unsigned int)IMG_SHARED_ADDR, (unsigned int)IMG_SHARED_SIZE, (unsigned int)IMG_SHARED_SIZE
#endif /* CONFIG_VIDEO_MP200 */
		);

	/* reserve region Smem */
	if (!request_mem_region(Smem, SmemLength, "qfb"))
	{
		printk_wrn("cannot reserve smem\n");
		mp200_fb_probe_error(FB_INIT_ERROR__SMEM_NOT_RESERVE, info_0, info_1, fb_num);
		return -ENOMEM;
	}

	/* remap SmemV */
	SmemV = ioremap_nocache(Smem, SmemLength);
	if (!SmemV)
	{
		printk_wrn("cannot ioremap_nocache smem\n");
		mp200_fb_probe_error(FB_INIT_ERROR__SMEM_NOT_REMAP, info_0, info_1, fb_num);
		return -ENOMEM;
	}
	printk_dbg((_DEBUG_FB), " Smem    (0x%lx)  SmemV    (0x%p)  SmemLength    (0x%lx)\n", Smem, SmemV, SmemLength);

#ifdef CONFIG_PGPF_NAVU2_PM
	spin_lock_init(&drvdata.suspend_lock);
#endif /* CONFIG_PGPF_NAVU2_PM */

	for( fb_num = 0; fb_num < EM1_FB_DEVICES; fb_num++ ){
		/* alloc framebuffer */
		info = framebuffer_alloc(sizeof(mp200_fb_par), &dev->dev);
		if (!info)
		{
			printk_wrn("cannot framebuffer alloc\n");
			mp200_fb_probe_error(FB_INIT_ERROR__FB_NOT_ALLOC, info_0, info_1, fb_num);
			return -ENOMEM;
		}
		else
		{
			if ( fb_num == 0 ) info_0 = info;
			else               info_1 = info;
		}

		if( fb_num == EM1_FB_DEVICE_LCD ){
#ifdef CONFIG_PGPF_BACKLIGHT
			pgpf_bl_init(info);
#endif /* CONFIG_PGPF_BACKLIGHT */
		}

		/* flag initialize */
		set_flag_init(fb_num);

		/* set buffer address */
		set_buffer_address( fb_num );

		/* set infomation */
		set_info(info, &par, fb_num);
		
		/* device flag set */
		par->devflag = fb_num;

		/* alloc cmap */
		iRet = fb_alloc_cmap(&info->cmap, 256, 0);
		if (iRet < 0)
		{
			printk_wrn("cannot framebuffer alloc cmap\n");
			mp200_fb_probe_error(FB_INIT_ERROR__FB_CMAP_NOT_ALLOC, info_0, info_1, fb_num);
			return -ENOMEM;
		}
#ifndef CONFIG_MACH_PGPF
		/* move to end of block */
		/* regist frame buffer */
		iRet = register_framebuffer(info);
		if (iRet < 0)
		{
			printk_wrn("cannot regist framebuffer\n");
			mp200_fb_probe_error(FB_INIT_ERROR__FB_NOT_REGIST, info_0, info_1, fb_num);
			return -EBUSY;
		}
#endif /* !CONFIG_MACH_PGPF */

		/* spinlock initialize */
		spin_lock_init(&par->fb_lock);

		/* semaphore initialize */
		sema_init(&par->sem_fb_image_info, 1);
		sema_init(&par->sem_fb_other_info_A, 1);
		sema_init(&par->sem_fb_other_info_B, 1);
		sema_init(&par->sem_tvmode,1);

#if (TIMEOUT_MSLEEP==0)
		/* wait_event initialize */
		init_waitqueue_head(&par->wait_fb_chk_scrn);
#endif

		/* workqueue initialize */
		par->mp200_fb_workqueue = create_singlethread_workqueue(DEV_NAME);
		INIT_WORK(&par->wk_timeout_update_bottom_half, timeout_update_bottom_half_do);

#ifdef CONFIG_PGPF_FB_PND_EXT
		par->auto_scroll_workqueue = create_singlethread_workqueue(AUTO_SCROLL_QUEUE_NAME);
		INIT_WORK(&par->wk_auto_scroll, auto_scroll_do);
#endif /* CONFIG_PGPF_FB_PND_EXT */

		/* variable initialize */
		set_val_init(info, fb_num);

		/* set drvdata */
		drvdata.info[fb_num] = info;

		/* for callback function */
		fb_data[fb_num].mp200_fb_dev = par;

#ifdef SHOW_EARLY
#ifdef CONFIG_MACH_PGPF
		mp200_fb_open(info, 0);
		atomic_dec(&par->use_count);
#endif /* CONFIG_MACH_PGPF */
#endif /* SHOW_EARLY */

#ifdef CONFIG_MACH_PGPF
		/* regist frame buffer */
		iRet = register_framebuffer(info);
		if (iRet < 0)
		{
			printk_wrn("cannot regist framebuffer\n");
			mp200_fb_probe_error(FB_INIT_ERROR__FB_NOT_REGIST, info_0, info_1, fb_num);
			return -EBUSY;
		}
#endif /* CONFIG_MACH_PGPF */
	}
	fb_num--;

	/*initialize LCD driver */
	if (mp200_lcd_init_module() != 0)
	{
		printk_wrn("cannot initialize LCD\n");
		mp200_fb_probe_error(FB_INIT_ERROR__LCD_NOT_INITIALIZE, info_0, info_1, fb_num);
		return -EBUSY;
	}

	/* set drvdate */
	dev_set_drvdata(&dev->dev, &drvdata);

	printk_info("registered device fb\n");
	return 0;
}


/******************************************************************************
* MODULE   : mp200_fb_probe_error
* FUNCTION : When probe error, cleanup
* RETURN   : none
* NOTE     :
* CREATE   : 2006.05.27 H.Nagashima
* UPDATE   :
******************************************************************************/
static void __init  mp200_fb_probe_error(int iErrorMode, struct fb_info *info_0, struct fb_info *info_1, int fb_num)
{
	if(fb_num > 0){
		switch(iErrorMode){
		case FB_INIT_ERROR__LCD_NOT_INITIALIZE: unregister_framebuffer(info_1);
		case FB_INIT_ERROR__FB_NOT_REGIST:      fb_dealloc_cmap(&info_1->cmap);
		case FB_INIT_ERROR__FB_CMAP_NOT_ALLOC:  framebuffer_release(info_1);
		case FB_INIT_ERROR__FB_NOT_ALLOC:
		default:                                break;
		}
		unregister_framebuffer(info_0);
		fb_dealloc_cmap(&info_0->cmap);
		framebuffer_release(info_0);
		iounmap(SmemV);
		release_mem_region(Smem, DispBufAllLength);
	}
	else{
		switch(iErrorMode){
		case FB_INIT_ERROR__LCD_NOT_INITIALIZE: unregister_framebuffer(info_0);
		case FB_INIT_ERROR__FB_NOT_REGIST:      fb_dealloc_cmap(&info_0->cmap);
		case FB_INIT_ERROR__FB_CMAP_NOT_ALLOC:  framebuffer_release(info_0);
		case FB_INIT_ERROR__FB_NOT_ALLOC:       iounmap(SmemV);
		case FB_INIT_ERROR__SMEM_NOT_REMAP:     release_mem_region(Smem, DispBufAllLength);
		case FB_INIT_ERROR__SMEM_NOT_RESERVE:
		default:                                break;
		}
	}
}


/******************************************************************************
* MODULE   : set_buffer_address
* FUNCTION : set frame buffer (A/B) address
* RETURN   : none
* NOTE     :
* CREATE   : 2006.05.27 H.Nagashima
* UPDATE   : 2008.12.04 J.Manabe
******************************************************************************/
static void set_buffer_address(int fb_num)
{
#ifdef CONFIG_FB_MP200_NTS
	if( fb_num == EM1_FB_DEVICE_LCD ){
#endif /* CONFIG_FB_MP200_NTS */
		/* set & clean DispBufA(2D) address */
		fb_data[fb_num].DispBufAV = SmemV + DISPBUF_A_OFFSET;
		memset_io((char __iomem *)fb_data[fb_num].DispBufAV, 0, fb_data[fb_num].DispBufLength);

		/* set & clean DispBufB(2D) address */
		fb_data[fb_num].DispBufBV = SmemV + DISPBUF_B_OFFSET;
		memset_io((char __iomem *)fb_data[fb_num].DispBufBV, 0, fb_data[fb_num].DispBufLength);

#ifdef CONFIG_PGPF_FB_LAYER2
#ifndef CONFIG_PGPF_FB_PND_REDUCE_MEMORY
		/* set & clean SubFrame(buf0) address */
		fb_data[fb_num].L2BufAV = SmemV + SUB_A_OFFSET;
		memset_io((char __iomem *)fb_data[fb_num].L2BufAV, 0, fb_data[fb_num].L2BufLength);
#endif /* !CONFIG_PGPF_FB_PND_REDUCE_MEMORY */

		/* set & clean SubFrame(buf1) address */
		fb_data[fb_num].L2BufBV = SmemV + SUB_B_OFFSET;
		memset_io((char __iomem *)fb_data[fb_num].L2BufBV, 0, fb_data[fb_num].L2BufLength);
#endif /* CONFIG_PGPF_FB_LAYER2 */

#ifdef CONFIG_PGPF_FB_PND_EXT
		/* set & clean BaseFrame(buf0) address */
		fb_data[fb_num].BaseBufAV = SmemV + BASE_A_OFFSET;
		memset_io((char __iomem *)fb_data[fb_num].BaseBufAV, 0, fb_data[fb_num].BaseBufLength);

		/* set & clean BaseFrame(buf1) address */
		fb_data[fb_num].BaseBufBV = SmemV + BASE_B_OFFSET;
		memset_io((char __iomem *)fb_data[fb_num].BaseBufBV, 0, fb_data[fb_num].BaseBufLength);

		/* set & clean Linux Console address */
		fb_data[fb_num].ConsoleBufV = SmemV + CONSOLE_OFFSET;

		if (!mp200_is_lcd_enable()) {
			memset_io((char __iomem *)fb_data[fb_num].ConsoleBufV, 0, fb_data[fb_num].ConsoleBufLength);
		}
#endif /* CONFIG_PGPF_FB_PND_EXT */

#ifdef CONFIG_FB_MP200_NTS
	} else {
		fb_data[fb_num].DispBufAV = SmemV + NTSCBUF_A_OFFSET;
		memset_io((char __iomem *)fb_data[fb_num].DispBufAV, 0, fb_data[fb_num].DispBufLength);

		/* set & clean DispBufB(2D) address */
		fb_data[fb_num].DispBufBV = SmemV + NTSCBUF_B_OFFSET;
		memset_io((char __iomem *)fb_data[fb_num].DispBufBV, 0, fb_data[fb_num].DispBufLength);
	}
#endif /* CONFIG_FB_MP200_NTS */
}


/******************************************************************************
* MODULE   : set_info
* FUNCTION : set frame buffer driver infomation
* RETURN   : none
* NOTE     :
* CREATE   : 2006.05.30 H.Nagashima
* UPDATE   : 2008.11.13 J.Manabe
******************************************************************************/
static void set_info(struct fb_info *info, mp200_fb_par **par, int fb_num)
{
	*par                  = (mp200_fb_par *)info->par;
	(*par)->fb_inf        = info;

#ifdef CONFIG_PGPF_FB_PND_EXT
	/* NAVU always uses Linux Console Buffer for /dev/fb0 */
	info->screen_base     = (char __iomem *)fb_data[fb_num].ConsoleBufV;
	info->screen_size     = fb_data[fb_num].ConsoleBufLength;
#else /* CONFIG_PGPF_FB_PND_EXT */
	info->screen_base     = (char __iomem *)fb_data[fb_num].DispBufAV;
	info->screen_size     = fb_data[fb_num].DispBufLength;
#endif /* CONFIG_PGPF_FB_PND_EXT */
	info->fbops           = &mp200_fb_ops;

#ifdef CONFIG_FB_MP200_NTS
	if( fb_num == EM1_FB_DEVICE_LCD ){
		info->var     = mp200_fb_default;
#ifdef CONFIG_MACH_PGPF
		pgpf_lcdhw_set_vscreeninfo(&info->var);
#endif /* CONFIG_MACH_PGPF */
	} else {
		info->var     = mp200_fb_tv_default;
	}
#else
	info->var             = mp200_fb_default;
#ifdef CONFIG_MACH_PGPF
	pgpf_lcdhw_set_vscreeninfo(&info->var);
#endif /* CONFIG_MACH_PGPF */
#endif /* CONFIG_FB_MP200_NTS */

	info->fix             = mp200_fb_fix;
	info->fix.line_length = info->var.xres_virtual * info->var.bits_per_pixel / 8;
#if defined(CONFIG_PGPF_FB_PND_EXT) || defined(CONFIG_PGPF_FB_UX_EXT)
	info->fix.smem_start  = Smem;
#ifdef CONFIG_PGPF_FB_UX_EXT
	info->fix.smem_len    = FB_FRAME_BUFFER_DISP_SIZE;
#else /* CONFIG_PGPF_FB_UX_EXT */
	info->fix.smem_len    = SmemLength;
#endif /* CONFIG_PGPF_FB_UX_EXT */
#else /* CONFIG_PGPF_FB_*_EXT */
	info->fix.smem_start  = fb_data[fb_num].DispBufA;
	info->fix.smem_len    = fb_data[fb_num].DispBufLength;
#endif /* CONFIG_PGPF_FB_*_EXT */
	info->pseudo_palette  = (*par)->pseudo_palette;
	info->flags           = FBINFO_FLAG_DEFAULT;
}


/******************************************************************************
* MODULE   : set_flag_init
* FUNCTION : flag initialize
* RETURN   : none
* NOTE     :
* CREATE   : 2006.05.30 H.Nagashima
* UPDATE   : 2008.11.14 J.Manabe
******************************************************************************/
static void set_flag_init(int fb_num)
{
	fb_data[fb_num].iFBStatus_A      = IS_NODATA;
	fb_data[fb_num].iFBStatus_B      = IS_NODATA;
	printk_dbg((_DEBUG_FB & 0x08), "A(%d) B(%d)\n", fb_data[fb_num].iFBStatus_A, fb_data[fb_num].iFBStatus_B);
	fb_data[fb_num].iNowDispPage     = DISP_BUFA;
	fb_data[fb_num].iNextDispPage    = DISP_BUFA;

#ifdef CONFIG_FB_MP200_NTS
	if ( fb_num == EM1_FB_DEVICE_NTS ){
		fb_data[fb_num].iUpdateTimerFlag = DEFALT_UPDATE_TIMER_NTS;

		/* tvmode default set */
		tvmode = EM1_TV_MODE_OFF;
		/* struct init */
		fb_data[EM1_FB_DEVICE_NTS].DispBufA      = SMEM_START + NTSCBUF_A_OFFSET;
		fb_data[EM1_FB_DEVICE_NTS].DispBufB      = SMEM_START + NTSCBUF_B_OFFSET;
		fb_data[EM1_FB_DEVICE_NTS].DispBufLength = NTSCBUF_LENGTH;
	}
	else {
#endif /* CONFIG_FB_MP200_NTS */
		fb_data[fb_num].iUpdateTimerFlag = DEFALT_UPDATE_TIMER_LCD;
		fb_data[fb_num].DispBufA         = SMEM_START + DISPBUF_A_OFFSET;
		fb_data[fb_num].DispBufB         = SMEM_START + DISPBUF_B_OFFSET;
		fb_data[fb_num].DispBufLength    = DISPBUF_LENGTH;
#ifdef CONFIG_FB_MP200_NTS
	}
#endif /* CONFIG_FB_MP200_NTS */

	fb_data[fb_num].iMixModeFlg      = ONLY_2D_MODE;
	fb_data[fb_num].iDpmSuspendFlag  = 0;

	fb_data[fb_num].is_first         = 1;

#ifdef CONFIG_PGPF_FB_LAYER2
	fb_data[fb_num].L2BufA         = SMEM_START + SUB_A_OFFSET;
	fb_data[fb_num].L2BufB         = SMEM_START + SUB_B_OFFSET;
	fb_data[fb_num].L2BufLength    = SUBBUF_LENGTH;
#endif /* CONFIG_PGPF_FB_LAYER2 */

#ifdef CONFIG_PGPF_FB_PND_EXT
	fb_data[fb_num].BaseBufA         = SMEM_START + BASE_A_OFFSET;
	fb_data[fb_num].BaseBufB         = SMEM_START + BASE_B_OFFSET;
	fb_data[fb_num].BaseBufLength    = BASEBUF_LENGTH;

	fb_data[fb_num].ConsoleBuf         = SMEM_START + CONSOLE_OFFSET;
	fb_data[fb_num].ConsoleBufLength    = CONSOLEBUF_LENGTH;
#endif /* CONFIG_PGPF_FB_PND_EXT */
}


/******************************************************************************
* MODULE   : set_val_init
* FUNCTION : variable initialize
* RETURN   : none
* NOTE     :
* CREATE   : 2006.06.05 H.Nagashima
* UPDATE   : 2008.11.14 J.Manabe
******************************************************************************/
static void set_val_init(struct fb_info *info, int fb_num)
{
#if defined(CONFIG_PGPF_FB_PND_EXT) || defined(CONFIG_PGPF_FB_UX_EXT)
	vsync_flag = 1;
	init_waitqueue_head(&mp200_vsync_wq);
#endif /* CONFIG_PGPF_FB_*_EXT */

	/* fb A val init */
#ifdef CONFIG_PGPF_FB_PND_EXT
	/* for ARGB4444 mode */
	fb_data[fb_num].fb_other_info_A.iMaskColFlg = TC_COLOR_ENABLE;
#else /* CONFIG_PGPF_FB_PND_EXT */
	fb_data[fb_num].fb_other_info_A.iMaskColFlg = TC_COLOR_DISABLE;
#endif /* CONFIG_PGPF_FB_PND_EXT */
	fb_data[fb_num].fb_other_info_A.iMaskCol    = 0x0020;
	fb_data[fb_num].fb_other_info_A.iAlpha      = 0xFF;
	fb_data[fb_num].fb_other_info_A.iInvFlg     = NO_INVERSE;
	fb_data[fb_num].fb_other_info_A.iPage       = DISP_BUFA;
	fb_data[fb_num].fb_other_info_A.iUpDate     = UPDATE_FLAG_OFF;

	/* fb B val init */
#ifdef CONFIG_PGPF_FB_PND_EXT
	/* for ARGB4444 mode */
	fb_data[fb_num].fb_other_info_B.iMaskColFlg = TC_COLOR_ENABLE;
#else /* CONFIG_PGPF_FB_PND_EXT */
	fb_data[fb_num].fb_other_info_B.iMaskColFlg = TC_COLOR_DISABLE;
#endif /* CONFIG_PGPF_FB_PND_EXT */
	fb_data[fb_num].fb_other_info_B.iMaskCol    = 0x0020;
	fb_data[fb_num].fb_other_info_B.iAlpha      = 0xFF;
	fb_data[fb_num].fb_other_info_B.iInvFlg     = NO_INVERSE;
	fb_data[fb_num].fb_other_info_B.iPage       = DISP_BUFB;
	fb_data[fb_num].fb_other_info_B.iUpDate     = UPDATE_FLAG_OFF;

	/* fb data init (to LCD) */
#ifdef CONFIG_PGPF_FB_PND_EXT
	fb_data[fb_num].fb_image_info.image_data.hsize    = LCD_OVERLAY_MAX_XRES;
	fb_data[fb_num].fb_image_info.image_data.vsize    = LCD_OVERLAY_MAX_YRES;
	fb_data[fb_num].fb_image_info.image_data.size     = LCD_OVERLAY_MAX_XRES * OVERLAY_BPP / 8;
#else /* CONFIG_PGPF_FB_PND_EXT */
	fb_data[fb_num].fb_image_info.image_data.hsize    = info->var.xres;
	fb_data[fb_num].fb_image_info.image_data.vsize    = info->var.yres;
	fb_data[fb_num].fb_image_info.image_data.size     = info->var.xres_virtual * info->var.bits_per_pixel / 8;
#endif /* CONFIG_PGPF_FB_PND_EXT */
	fb_data[fb_num].fb_image_info.image_data.yrgbaddr = fb_data[fb_num].DispBufA;
	fb_data[fb_num].fb_image_info.image_data.uvaddr   = 0x00000000;
	fb_data[fb_num].fb_image_info.image_data.x        = 0;
	fb_data[fb_num].fb_image_info.image_data.y        = 0;

	/* fb info init (to LCD) */
#ifdef CONFIG_MACH_PGPF
#ifdef SHOW_OVERLAY_ON_STARTUP
	fb_data[fb_num].fb_image_info.control = FB_CONTROL_ON;
#else /* SHOW_OVERLAY_ON_STARTUP */
	fb_data[fb_num].fb_image_info.control = FB_CONTROL_OFF;
#endif /* SHOW_OVERLAY_ON_STARTUP */
#endif /* CONFIG_MACH_PGPF */
#ifdef CONFIG_PGPF_FB_PND_EXT
	fb_data[fb_num].fb_image_info.maskcolrflg  = FB_MASK_COLOR_DISP_ON;
#else /* CONFIG_PGPF_FB_PND_EXT */
	fb_data[fb_num].fb_image_info.maskcolrflg  = FB_MASK_COLOR_DISP_OFF;
#endif /* CONFIG_PGPF_FB_PND_EXT */
	fb_data[fb_num].fb_image_info.maskcolr     = 0x0020;
#ifdef CONFIG_PGPF_FB_PND_EXT
	fb_data[fb_num].fb_image_info.alpha        = 0xFF;
#else /* CONFIG_PGPF_FB_PND_EXT */
	fb_data[fb_num].fb_image_info.alpha        = GENERIC_FB_TRANSPARENCY;
#endif /* CONFIG_PGPF_FB_PND_EXT */
	fb_data[fb_num].fb_image_info.invflg       = NO_INVERSE;
	fb_data[fb_num].fb_image_info.mix_buf_page = DISP_BUFA;
	fb_data[fb_num].fb_image_info.update_flag  = FB_UPDATE_OFF;

#ifdef CONFIG_PGPF_FB_LAYER2
	/* l2 data init */
	memset(&fb_data[fb_num].l2_image_info, 0, sizeof(FB_IMAGE_INFO));

	fb_data[fb_num].l2_image_info.control             = FB_CONTROL_OFF;
	fb_data[fb_num].l2_image_info.image_data.hsize    = LCD_SUB_DEFAULT_FRAME_XRES;
	fb_data[fb_num].l2_image_info.image_data.vsize    = LCD_SUB_DEFAULT_FRAME_YRES;
	fb_data[fb_num].l2_image_info.image_data.size     = LCD_SUB_DEFAULT_FRAME_XRES * 16 / 8;

	fb_data[fb_num].l2_image_info.image_data.yrgbaddr = fb_data[fb_num].L2BufA;
	fb_data[fb_num].l2_image_info.image_data.uvaddr   = 0x00000000;
	fb_data[fb_num].l2_image_info.yuvfmt              = IMC_Lx_FORMAT_RGB565;
	fb_data[fb_num].l2_image_info.image_data.x        = 0;
	fb_data[fb_num].l2_image_info.image_data.y        = 0;

	fb_data[fb_num].l2_image_info.screen_data.x       = 0;
	fb_data[fb_num].l2_image_info.screen_data.y       = 0;
	fb_data[fb_num].l2_image_info.screen_data.hsize   = LCD_SUB_DEFAULT_SCREEN_XRES;
	fb_data[fb_num].l2_image_info.screen_data.vsize   = LCD_SUB_DEFAULT_SCREEN_YRES;
#endif /* CONFIG_PGPF_FB_LAYER2 */

#ifdef CONFIG_PGPF_FB_PND_EXT
	/* bg data init */
	memset(&fb_data[fb_num].bg_image_info, 0, sizeof(FB_IMAGE_INFO));
	fb_data[fb_num].bg_image_info.control             = FB_CONTROL_ON;
	fb_data[fb_num].bg_image_info.image_data.hsize    = LCD_BASE_MAX_XRES;
	fb_data[fb_num].bg_image_info.image_data.vsize    = LCD_BASE_MAX_YRES;
	fb_data[fb_num].bg_image_info.image_data.size     = LCD_BASE_MAX_XRES * BASE_BPP / 8;
	fb_data[fb_num].bg_image_info.image_data.yrgbaddr = fb_data[fb_num].BaseBufA;
	fb_data[fb_num].bg_image_info.image_data.uvaddr   = 0x00000000;
	fb_data[fb_num].bg_image_info.image_data.x        = 0;
	fb_data[fb_num].bg_image_info.image_data.y        = 0;

	/* console data init */
	memset(&fb_data[fb_num].console_image_info, 0, sizeof(FB_IMAGE_INFO));
#ifdef START_WITH_LINUX_CONSOLE
	fb_data[fb_num].console_image_info.control = FB_CONTROL_ON;
#else /* START_WITH_LINUX_CONSOLE */
	fb_data[fb_num].console_image_info.control = FB_CONTROL_OFF;
#endif /* START_WITH_LINUX_CONSOLE */
	fb_data[fb_num].console_image_info.image_data.hsize    = LCD_CONSOLE_MAX_XRES;
	fb_data[fb_num].console_image_info.image_data.vsize    = LCD_CONSOLE_MAX_YRES;
	fb_data[fb_num].console_image_info.image_data.size     = LCD_CONSOLE_MAX_XRES * FB_BPP / 8;
	fb_data[fb_num].console_image_info.image_data.yrgbaddr = fb_data[fb_num].ConsoleBuf;
	fb_data[fb_num].console_image_info.image_data.uvaddr   = 0x00000000;
	fb_data[fb_num].console_image_info.image_data.x        = 0;
	fb_data[fb_num].console_image_info.image_data.y        = 0;
	fb_data[fb_num].console_image_info.alpha = GENERIC_FB_TRANSPARENCY;

	/* NAVU Frame Info */
	/* Base Frame */
	fb_data[fb_num].BaseFrame.Status = 1;
	fb_data[fb_num].BaseFrame.Flip = 0;

	fb_data[fb_num].BaseFrame.DispX = 0;
	fb_data[fb_num].BaseFrame.DispY = 0;
	fb_data[fb_num].BaseFrame.DispWidth = LCD_BASE_MIN_XRES;
	fb_data[fb_num].BaseFrame.DispHeight = LCD_BASE_MIN_YRES;

	fb_data[fb_num].BaseFrame.FrameX = 0;
	fb_data[fb_num].BaseFrame.FrameY = 0;
	fb_data[fb_num].BaseFrame.FrameWidth = LCD_BASE_MAX_XRES;
	fb_data[fb_num].BaseFrame.FrameHeight = LCD_BASE_MAX_YRES;

	memset(&fb_data[fb_num].BaseScroll, 0, sizeof(scroll_info));

#ifdef CONFIG_PGPF_FB_LAYER2
	/* Sub Frame */
	fb_data[fb_num].SubFrame.Status = 0;
	fb_data[fb_num].SubFrame.Flip = 0;

	fb_data[fb_num].SubFrame.DispX = 0;
	fb_data[fb_num].SubFrame.DispY = 0;
	fb_data[fb_num].SubFrame.DispWidth = LCD_SUB_MAP_MIN_XRES;
	fb_data[fb_num].SubFrame.DispHeight = LCD_SUB_MAP_MIN_YRES;

	fb_data[fb_num].SubFrame.FrameX = 0;
	fb_data[fb_num].SubFrame.FrameY = 0;
	fb_data[fb_num].SubFrame.FrameWidth = LCD_SUB_MAP_MAX_XRES;
	fb_data[fb_num].SubFrame.FrameHeight = LCD_SUB_MAP_MAX_YRES;

	memset(&fb_data[fb_num].SubScroll, 0, sizeof(scroll_info));
#endif /* CONFIG_PGPF_FB_LAYER2 */

	/* Overlay & Linux Console */
	fb_data[fb_num].OverlayFrame.Status = 1;

#ifdef START_WITH_LINUX_CONSOLE
	fb_data[fb_num].OverlayFrame.Flip = 2;
#else /* START_WITH_LINUX_CONSOLE */
	fb_data[fb_num].OverlayFrame.Flip = 0;
#endif /* START_WITH_LINUX_CONSOLE */

	fb_data[fb_num].OverlayFrame.DispX = 0;
	fb_data[fb_num].OverlayFrame.DispY = 0;
	fb_data[fb_num].OverlayFrame.DispWidth = LCD_OVERLAY_MAX_XRES;
	fb_data[fb_num].OverlayFrame.DispHeight = LCD_OVERLAY_MAX_YRES;

	fb_data[fb_num].OverlayFrame.FrameX = 0;
	fb_data[fb_num].OverlayFrame.FrameY = 0;
	fb_data[fb_num].OverlayFrame.FrameWidth = LCD_OVERLAY_MAX_YRES;
	fb_data[fb_num].OverlayFrame.FrameHeight = LCD_OVERLAY_MAX_YRES;

	memset(&fb_data[fb_num].OverlayScroll, 0, sizeof(scroll_info));
#endif /* CONFIG_PGPF_FB_PND_EXT */

	/* timer */
	fb_data[fb_num].iTimeoutTime               = TIMEOUT_TIME;
}


#if 0
void ............Timer_Function................(){}
#endif
/********************************************************
 *  Timer Function Definitions                          *
 *******************************************************/
/******************************************************************************
* MODULE   : timer_init
* FUNCTION : call back from LCD driver
* RETURN   : none
* NOTE     : public function
* CREATE   : 2006.06.07 H.Nagashima
* UPDATE   : 2008.11.14 J.Manabe
******************************************************************************/
static void timer_init(struct fb_info *info)
{
	mp200_fb_par *par = (mp200_fb_par *)info->par;
	
	
	init_timer(&fb_data[par->devflag].mp200_fb_timer);
	fb_data[par->devflag].mp200_fb_timer.function = timeout_update;
	fb_data[par->devflag].mp200_fb_timer.entry.next = NULL;
	fb_data[par->devflag].mp200_fb_timer.data = (unsigned long)info;
	down( &par->sem_tvmode );
	if (par->devflag == EM1_FB_DEVICE_LCD || tvmode != EM1_TV_MODE_OFF)
	{
		if((fb_data[par->devflag].iUpdateTimerFlag == TIMER_ON) && (fb_data[par->devflag].iMixModeFlg == ONLY_2D_MODE))
		{
			printk_dbg((_DEBUG_FB & 0x10), "add_timer\n");
			fb_data[par->devflag].mp200_fb_timer.expires = jiffies + (TIMEOUT_TIME * HZ / 1000);
			add_timer(&fb_data[par->devflag].mp200_fb_timer);
			fb_data[par->devflag].iTimerStatusFlag = FB_TIMER_START;
			printk_dbg((_DEBUG_FB & 0x01), "%d <start>\n", __LINE__);
		}
	}
	up( &par->sem_tvmode );
}


/******************************************************************************
* MODULE   : timeout_update
* FUNCTION : when Timer timeout, update execution
* RETURN   : none
* NOTE     : public function
* CREATE   : 2006.06.07 H.Nagashima
* UPDATE   : 2008.11.14 J.Manabe
******************************************************************************/
static void timeout_update(unsigned long data)
{
	unsigned long        flags;
	struct fb_info      *info = (struct fb_info *)data;
	       mp200_fb_par *par  = (mp200_fb_par *)info->par;

	printk_dbg((_DEBUG_FB & 0x10), "\n");
	/* fb timer stop */
	spin_lock_irqsave(&fb_data[par->devflag].mp200_fb_dev->fb_lock, flags);
	del_timer(&fb_data[par->devflag].mp200_fb_timer);
	fb_data[par->devflag].iTimerStatusFlag = FB_TIMER_STOP;
	spin_unlock_irqrestore(&fb_data[par->devflag].mp200_fb_dev->fb_lock, flags);

	printk_dbg((_DEBUG_FB & 0x10), "queue_work\n");
	queue_work(par->mp200_fb_workqueue, &par->wk_timeout_update_bottom_half);

	/* start timer */
	if((fb_data[par->devflag].iUpdateTimerFlag == TIMER_ON) && (fb_data[par->devflag].iMixModeFlg == ONLY_2D_MODE))
	{
		spin_lock_irqsave(&fb_data[par->devflag].mp200_fb_dev->fb_lock, flags);
		if(fb_data[par->devflag].iTimerStatusFlag == FB_TIMER_STOP)
		{
			printk_dbg((_DEBUG_FB & 0x10), "add_timer\n");
			fb_data[par->devflag].mp200_fb_timer.expires = jiffies + (fb_data[par->devflag].iTimeoutTime * HZ / 1000);
			add_timer(&fb_data[par->devflag].mp200_fb_timer);
			fb_data[par->devflag].iTimerStatusFlag = FB_TIMER_START;
		}
		spin_unlock_irqrestore(&fb_data[par->devflag].mp200_fb_dev->fb_lock, flags);
	}
}


/******************************************************************************
* MODULE   : timeout_update_bottom_half_do
* FUNCTION : when Timer timeout, update execution
* RETURN   : none
* NOTE     : private function
* CREATE   : 2006.07.10 Y.Utsuhara
* UPDATE   : 2008.11.14 J.Manabe
******************************************************************************/
static void timeout_update_bottom_half_do(struct work_struct *num)
{
	mp200_fb_par *par    = container_of(num, mp200_fb_par, wk_timeout_update_bottom_half);
#ifndef CONFIG_PGPF_FB_UX_EXT
	struct fb_info *info = par->fb_inf;
#endif /* CONFIG_PGPF_FB_UX_EXT */

	printk_dbg((_DEBUG_FB & 0x10), "\n");
	if(down_trylock(&par->sem_fb_image_info))		/* lock fb_image_info */
		return;

#ifndef CONFIG_PGPF_FB_UX_EXT
	/* set image infomation to LCD */
	set_image_info_to_LCD(fb_data[par->devflag].iNextDispPage, info);
#endif /* !CONFIG_PGPF_FB_UX_EXT */

	/* udpate on (normal MP200_FB_UPDATE_SCRN exe) */
	fb_data[par->devflag].fb_image_info.update_flag = FB_UPDATE_ON;

#ifdef CONFIG_FB_MP200_NTS
	if( par->devflag == EM1_FB_DEVICE_LCD ){
#endif /* CONFIG_FB_MP200_NTS */
		/* call fb function */
		printk_dbg((_DEBUG_FB & 0x10), "request LCD\n");
#ifdef CONFIG_PGPF_FB_PND_EXT
#ifdef CONFIG_PGPF_FB_LAYER2
		mp200_lcd_set_fb_image_ex2(&fb_data[par->devflag].fb_image_info, &fb_data[par->devflag].bg_image_info, &fb_data[par->devflag].l2_image_info, &fb_data[par->devflag].console_image_info);
#else /* CONFIG_PGPF_FB_LAYER2 */
		mp200_lcd_set_fb_image_ex(&fb_data[par->devflag].fb_image_info, &fb_data[par->devflag].bg_image_info, &fb_data[par->devflag].console_image_info);
#endif /* CONFIG_PGPF_FB_LAYER2 */
#else /* CONFIG_PGPF_FB_PND_EXT */
#ifdef CONFIG_PGPF_FB_LAYER2
		mp200_lcd_set_fb_image_ex2(&fb_data[par->devflag].fb_image_info, NULL, &fb_data[par->devflag].l2_image_info, NULL);
#else /* CONFIG_PGPF_FB_LAYER2 */
		mp200_lcd_set_fb_image(&fb_data[par->devflag].fb_image_info);
#endif /* CONFIG_PGPF_FB_LAYER2 */
#endif /* CONFIG_PGPF_FB_PND_EXT */
#ifdef CONFIG_FB_MP200_NTS
	} else {
		/* call fb1 function */
		printk_dbg((_DEBUG_FB & 0x10), "request NTS\n");
		mp200_nts_set_fb_image(&fb_data[par->devflag].fb_image_info);
	}
#endif /* CONFIG_FB_MP200_NTS */

	up(&par->sem_fb_image_info);		/* unlock fb_image_info */
}


#if 0
void ............Exit_Function................(){}
#endif
/********************************************************
 *  Exit Function Definitions                           *
 *******************************************************/
/******************************************************************************
* MODULE   : mp200_fb_remove
* FUNCTION : remove
* RETURN   : 0 : success
* NOTE     : none
* CREATE   :
* UPDATE   : 2006.05.27 H.Nagashima
* UPDATE   : 2008.12.09 J.Manabe
******************************************************************************/
static int mp200_fb_remove(struct platform_device *device)
{
	MP200_FB_DRVDATA *drvdata = platform_get_drvdata(device);
	struct fb_info *info;
	int i;
	
	for( i = 0; i < EM1_FB_DEVICES; i++ ){
		/* remove frame buffer */
		info = drvdata->info[i];
		if (info)
		{
			if (i == EM1_FB_DEVICE_LCD) {
#ifdef CONFIG_PGPF_BACKLIGHT
				pgpf_bl_exit(info);
#endif /* CONFIG_PGPF_BACKLIGHT */
#ifdef CONFIG_PGPF_LCD
				pgpf_lcdhw_exit();
#endif /* CONFIG_PGPF_LCD */
			}

			unregister_framebuffer(info);
			fb_dealloc_cmap(&info->cmap);
			framebuffer_release(info);
		}
	}

	/* lcd remove */
	mp200_lcd_exit_module();

	/* remove Smem */
	iounmap(SmemV);
	release_mem_region(Smem, SmemLength);

	return 0;
}


#if defined(CONFIG_PM) || defined(CONFIG_DPM)
/********************************************************
 *  Suspend/Resume Function Definitions                 *
 *******************************************************/
/******************************************************************************
* MODULE   : mp200_fb_suspend
* FUNCTION : suspend frame buffer driver
* RETURN   :  0 : success
*          : -1 : faile
* NOTE     : none
* CREATE   :
* UPDATE   : 2006.05.29 H.Nagashima
* UPDATE   : 2008.12.05 J.Manabe
******************************************************************************/
#ifdef CONFIG_PGPF_NAVU2_PM
int mp200_fb_suspend(struct platform_device *dev, pm_message_t state)
#else /* CONFIG_PGPF_NAVU2_PM */
static int mp200_fb_suspend(struct platform_device *dev, pm_message_t state)
#endif /* CONFIG_PGPF_NAVU2_PM */
{
#ifdef CONFIG_PGPF_NAVU2_PM
	unsigned long lock_flags;
	spin_lock_irqsave(&drvdata.suspend_lock, lock_flags);
#endif /* CONFIG_PGPF_NAVU2_PM */

	/*** this module suspend ***/
	if(!fb_data[EM1_FB_DEVICE_LCD].is_first){
#ifdef CONFIG_PGPF_NAVU2_PM
		if (fb_data[EM1_FB_DEVICE_LCD].iDpmSuspendFlag) {
			/* this function has already called */
			goto lcd_susupend_end;
		} else {
			mp200_fb_set_tpled(SONY_NAVU_TPLED_OFF);
			mp200_fb_set_brightness(0);
		}
#endif /* CONFIG_PGPF_NAVU2_PM */

		/*** this module suspend ***/
		if(mp200_fb_suspend_sub(dev, state, EM1_FB_DEVICE_LCD)){	/* call fb suspend function  */
			goto fail_fb_lcd;
		}
		/*** relational module suspend ***/
		if(mp200_lcd_suspend(dev, state)){	/* call LCD suspend function */
			goto fail_lcd;
		}
		if(mp200_imc_suspend(dev, state)){	/* call IMC suspend function */
			goto fail_imc;
		}
	}
#ifdef CONFIG_PGPF_NAVU2_PM
  lcd_susupend_end:
#endif /* CONFIG_PGPF_NAVU2_PM */

#ifdef CONFIG_MP200_NTS
#ifdef CONFIG_FB_MP200_NTS
	/*** this module suspend ***/
	if ( !fb_data[EM1_FB_DEVICE_NTS].is_first ){
#ifdef CONFIG_PGPF_NAVU2_PM
		if (fb_data[EM1_FB_DEVICE_NTS].iDpmSuspendFlag) {
			/* this function has already called */
			goto nts_susupend_end;
		}
#endif /* CONFIG_PGPF_NAVU2_PM */

		if(mp200_fb_suspend_sub(dev, state, EM1_FB_DEVICE_NTS)){	/* call fb suspend function  */
			goto fail_fb_nts;
		}
	}
#endif /* CONFIG_FB_MP200_NTS */
	/*** relational module suspend ***/
	if( mp200_nts_suspend( dev, state ) ){		/* call NTS suspend function */
		goto fail_nts;
	}
#ifdef CONFIG_PGPF_NAVU2_PM
  nts_susupend_end:
#endif /* CONFIG_PGPF_NAVU2_PM */
#endif /* CONFIG_MP200_NTS */
#ifdef CONFIG_PGPF_NAVU2_PM
	{
		int i;
		for (i = 0; i < EM1_FB_DEVICES; i++) {
#if 0
			/* clear screen */
			set_buffer_address(i);
#else
			/* turn off all layers */
			fb_data[i].console_image_info.control = FB_CONTROL_OFF;
			fb_data[i].fb_image_info.control = FB_CONTROL_OFF;
			fb_data[i].OverlayFrame.Status = 0;
			fb_data[i].bg_image_info.control = FB_CONTROL_OFF;
			fb_data[i].BaseFrame.Status = 0;
			fb_data[i].l2_image_info.control = FB_CONTROL_OFF;
			fb_data[i].SubFrame.Status = 0;
#endif
		}
	}

	spin_unlock_irqrestore(&drvdata.suspend_lock, lock_flags);
#endif /* CONFIG_PGPF_NAVU2_PM */
	return 0;

#ifdef CONFIG_MP200_NTS
fail_nts:
#ifdef CONFIG_FB_MP200_NTS
	mp200_fb_resume_sub(dev, EM1_FB_DEVICE_NTS);
fail_fb_nts:
#endif /* CONFIG_FB_MP200_NTS */
	mp200_imc_resume(dev);
#endif /* CONFIG_MP200_NTS */
fail_imc:
	mp200_lcd_resume(dev);
fail_lcd:
	mp200_fb_resume_sub(dev, EM1_FB_DEVICE_LCD);
fail_fb_lcd:
#ifdef CONFIG_PGPF_NAVU2_PM
	spin_unlock_irqrestore(&drvdata.suspend_lock, lock_flags);
#endif /* CONFIG_PGPF_NAVU2_PM */
	return -EBUSY;
}


/******************************************************************************
* MODULE   : mp200_fb_suspend_sub
* FUNCTION : suspend frame buffer driver
* RETURN   : 0 : success
* NOTE     : none
* CREATE   :
* UPDATE   : 2007.11.28 M.Haguro
* UPDATE   : 2008.12.04 J.Manabe
******************************************************************************/
static int mp200_fb_suspend_sub(struct platform_device *dev, pm_message_t state, int fb_num)
{
	int ret;

	if (state.event == DEV_SUSPEND_IDLE_1)
	{
		ret = 0;
	}
	else /* state.event == PM_EVENT_SUSPEND */
	{
		if (!mp200_sleep_while_idle)
		{
			/*** this module suspend ***/
			fb_data[fb_num].iDpmSuspendFlag = 1;
			del_timer(&fb_data[fb_num].mp200_fb_timer);	/* stop timer interrupt */
		}
		ret = 0;
	}
	return ret;
}


/******************************************************************************
* MODULE   : mp200_fb_resume
* FUNCTION : resume frame buffer driver
* RETURN   : 0 : success
* NOTE     : none
* CREATE   :
* UPDATE   : 2006.05.29 H.Nagashima
* UPDATE   : 2008.12.04 J.Manabe
******************************************************************************/
#ifdef CONFIG_PGPF_NAVU2_PM
int mp200_fb_resume(struct platform_device *dev)
#else /* CONFIG_PGPF_NAVU2_PM */
static int mp200_fb_resume(struct platform_device *dev)
#endif /* CONFIG_PGPF_NAVU2_PM */
{
#ifdef CONFIG_PGPF_NAVU2_PM
	unsigned long lock_flags;
	spin_lock_irqsave(&drvdata.suspend_lock, lock_flags);
#endif /* CONFIG_PGPF_NAVU2_PM */

	if(!fb_data[EM1_FB_DEVICE_LCD].is_first){
		/*** relathional module resume ***/
		mp200_imc_resume(dev);		/* call IMC resume function */
		mp200_lcd_resume(dev);		/* call LCD resume function */
		mp200_fb_resume_sub(dev, EM1_FB_DEVICE_LCD);	/* call fb  resume function */
	}
#ifdef CONFIG_MP200_NTS
	mp200_nts_resume(dev);	/* call NTS resume function */
#ifdef CONFIG_FB_MP200_NTS
	if (!fb_data[EM1_FB_DEVICE_NTS].is_first){
		mp200_fb_resume_sub(dev, EM1_FB_DEVICE_NTS);	/* call fb  resume function */
	}
#endif /* CONFIG_FB_MP200_NTS */
#endif /* CONFIG_MP200_NTS */
#ifdef CONFIG_PGPF_NAVU2_PM
	spin_unlock_irqrestore(&drvdata.suspend_lock, lock_flags);
#endif /* CONFIG_PGPF_NAVU2_PM */
	return 0;
}


/******************************************************************************
* MODULE   : mp200_fb_resume_sub
* FUNCTION : resume frame buffer driver
* RETURN   : 0 : success
* NOTE     : none
* CREATE   :
* UPDATE   : 2007.11.28 M.Haguro
* UPDATE   : 2008.12.04 J.Manabe
******************************************************************************/
static int mp200_fb_resume_sub(struct platform_device *dev, int fb_num)
{
#ifndef CONFIG_MACH_PGPF
	MP200_FB_DRVDATA *drvdata = platform_get_drvdata(dev);
#endif /* !CONFIG_MACH_PGPF */
	struct fb_info *info;
	mp200_fb_par *par;

	if(fb_data[fb_num].iDpmSuspendFlag){
		/*** this module resume ***/
		fb_data[fb_num].iDpmSuspendFlag = 0;

		if (fb_num == EM1_FB_DEVICE_LCD || tvmode != EM1_TV_MODE_OFF)
		{
			if(fb_data[fb_num].iMixModeFlg == ONLY_2D_MODE){
				if(fb_data[fb_num].iUpdateTimerFlag == TIMER_ON){
					printk_dbg((_DEBUG_FB & 0x10), "add_timer\n");
					add_timer(&fb_data[fb_num].mp200_fb_timer);	/* start timer interrupt */
				}
				else{
#ifdef CONFIG_MACH_PGPF
					info = drvdata.info[fb_num];
#else /* CONFIG_MACH_PGPF */
					info = drvdata->info[fb_num];
#endif /* CONFIG_MACH_PGPF */
					par  = (mp200_fb_par *)info->par;
					
					printk_dbg((_DEBUG_FB & 0x10), "queue_work\n");
					queue_work(par->mp200_fb_workqueue, &par->wk_timeout_update_bottom_half);
				}
			}
		}
	}
	return 0;
}
#endif /* CONFIG_PM || CONFIG_DPM */

#ifdef CONFIG_PGPF_BACKLIGHT
#ifdef CONFIG_PGPF_NAVU2
int mp200_fb_set_tpled(int mode)
{
	if (fb_data[EM1_FB_DEVICE_LCD].iDpmSuspendFlag) {
		return -EBUSY;
	} else if (mode >= SONY_NAVU_TPLED_END) {
		return -EINVAL;
	} else {
		pgpf_bl_set_tpled_mode(mode);
	}
	return 0;
}
EXPORT_SYMBOL(mp200_fb_set_tpled);
#endif /* CONFIG_PGPF_NAVU2 */
int mp200_fb_set_brightness(int brightness)
{
	struct fb_info* info = drvdata.info[EM1_FB_DEVICE_LCD];

	if (fb_data[EM1_FB_DEVICE_LCD].iDpmSuspendFlag) {
		return -EBUSY;
	} else if (!info->bl_dev) {
		return -ENXIO;
	} else {
		info->bl_dev->props.brightness = brightness;
		backlight_update_status(info->bl_dev);
	}
	return 0;
}
EXPORT_SYMBOL(mp200_fb_set_brightness);

int mp200_fb_get_brightness(void)
{
	struct fb_info* info = drvdata.info[EM1_FB_DEVICE_LCD];

	if (!info->bl_dev) {
		return -ENXIO;
	} else {
		return info->bl_dev->props.brightness;
	}
}
EXPORT_SYMBOL(mp200_fb_get_brightness);
#endif /* CONFIG_PGPF_BACKLIGHT */

MODULE_AUTHOR("NEC Electronics Corporation.");
MODULE_DESCRIPTION("EM1 framebuffer driver");
MODULE_LICENSE("GPL");


/* function alias  */

#if defined (SHOW_EARLY) && ! defined (MODULE)
//late_initcall(mp200_fb_init_module);
//module_init(mp200_fb_init_module);
device_initcall_sync(mp200_fb_init_module);
#else
module_init(mp200_fb_init_module);
#endif /* SHOW_EARLY */

/* EXPORT_SYMBOL */
EXPORT_SYMBOL(mp200_fb_callback);
#ifdef CONFIG_PGPF_NAVU2_PM
EXPORT_SYMBOL(mp200_fb_resume);
EXPORT_SYMBOL(mp200_fb_suspend);
#endif /* CONFIG_PGPF_NAVU2_PM */
