/* * linux/drivers/video/auofb.c -- for AUO epaper frame buffer device * * Modified by Ivan.Ruan * * Created 2009/04/01 by Ivan.Ruan * * * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //#include #include #include #include #include #include #include #include "epaper.h" #include "auofb.h" #include #ifdef CONFIG_PM #include #include #endif #include #include //#define EPD_HW_ROTATE //#define EPD_HW_ROTATE_NO_MODE4 #define AUOFB_ROTATE #define AUO_LUT_LENGTH 983040 //in bytes //#define DPRINTK(x...) printk("AUOFB: " x) #define DPRINTK(x...) #define DEF_DISPLAY_BRIGHTNESS 4 #define PIXEL_BPP4 4 #define PIXEL_BPP8 8 #define PIXEL_BPP16 16 /* RGB 5-6-5 format for SMDK EVAL BOARD */ #define PIXEL_BPP24 24 /* RGB 8-8-8 format for SMDK EVAL BOARD */ #ifdef EPD_HW_ROTATE #define H_RESOLUTION AUO_EPAPER_PHYSICAL_V_RESOLUTION #define V_RESOLUTION AUO_EPAPER_PHYSICAL_H_RESOLUTION #define H_RESOLUTION_OSD AUO_EPAPER_PHYSICAL_V_RESOLUTION #define V_RESOLUTION_OSD AUO_EPAPER_PHYSICAL_H_RESOLUTION #else //SW rotate #ifdef AUOFB_ROTATE #define H_RESOLUTION AUO_EPAPER_PHYSICAL_V_RESOLUTION #define V_RESOLUTION AUO_EPAPER_PHYSICAL_H_RESOLUTION #define H_RESOLUTION_OSD AUO_EPAPER_PHYSICAL_V_RESOLUTION #define V_RESOLUTION_OSD AUO_EPAPER_PHYSICAL_H_RESOLUTION #else //not rotate #define H_RESOLUTION AUO_EPAPER_PHYSICAL_H_RESOLUTION #define V_RESOLUTION AUO_EPAPER_PHYSICAL_V_RESOLUTION #define H_RESOLUTION_OSD AUO_EPAPER_PHYSICAL_H_RESOLUTION #define V_RESOLUTION_OSD AUO_EPAPER_PHYSICAL_V_RESOLUTION #endif #endif //#ifdef EPD_HW_ROTATE #define MAX_ALPHA_LEVEL 0x0f #define H_FP 1 /* front porch */ #define H_SW 1 /* Hsync width */ #define H_BP 1 /* Back porch */ #define V_FP 1 /* front porch */ #define V_SW 1 /* Vsync width */ #define V_BP 1 /* Back porch */ #define VFRAME_FREQ 1 #define LCD_PIXEL_CLOCK (VFRAME_FREQ *(H_FP+H_SW+H_BP+H_RESOLUTION) * (V_FP+V_SW+V_BP+V_RESOLUTION)) #define PIXEL_CLOCK VFRAME_FREQ * LCD_PIXEL_CLOCK /* vclk = frame * pixel_count */ #if defined(AUO_EPAPER_6_INCH) /* Bookeen's Value */ #define BOOT_PROGRESS_BAR_X 32 #define BOOT_PROGRESS_BAR_Y 767 #define BOOT_PROGRESS_BAR_W (567 - 32) #define BOOT_PROGRESS_BAR_H (784 - 767) #define BOOT_PROGRESS_BAR_DELAY_TIME 250 //2 sec = 420 #else #define BOOT_PROGRESS_BAR_X 259 #define BOOT_PROGRESS_BAR_Y 119 #define BOOT_PROGRESS_BAR_W 8 #define BOOT_PROGRESS_BAR_H 531 #define BOOT_PROGRESS_BAR_DELAY_TIME 250 #endif //test time struct timeval now; suseconds_t diff; //var int pre_mode=0; static int delayLoopCount; int display_brightness = DEF_DISPLAY_BRIGHTNESS; static int picnum=0;; static int Initialize = 0; static unsigned long update_display_timeout = (1600*2); //1600 about 1s static pid_t update_display_pid = 0; static wait_queue_head_t update_display_wq; static DECLARE_COMPLETION(update_display_thread_exited); static pid_t boot_progress_bar_pid = 0; static wait_queue_head_t boot_progress_bar_wq; static DECLARE_COMPLETION(boot_progress_bar_thread_exited); static unsigned short u16Temperature = 0; static unsigned short u16EPDType = 0; static unsigned short u16PanelType = 0; static unsigned short u16LUTVersion = 0; static unsigned short u16PrevMode = 0; static unsigned long u32PowerState = EN_EPD_DEVICE_POWER_STATE_D0; /* u32FullUpdateThreshold: 0 ~ (AUO_EPAPER_PHYSICAL_V_RESOLUTION*AUO_EPAPER_PHYSICAL_H_RESOLUTION) 0: Always full screen update AUO_EPAPER_PHYSICAL_V_RESOLUTION*AUO_EPAPER_PHYSICAL_H_RESOLUTION: update region is depand on partial_info */ static unsigned long u32FullUpdateThreshold = (AUO_EPAPER_PHYSICAL_V_RESOLUTION*AUO_EPAPER_PHYSICAL_H_RESOLUTION); DECLARE_MUTEX(auofb_lock); struct auo_fb_info info; static unsigned char* pu8Framebuffer = NULL; static unsigned short* pu16Translatebuffer = NULL; static unsigned char* pu8RotateBuffer = NULL; typedef struct partial_update_info { int mode; int x; int y; int w; int h; }_partial_update_info; //_partial_update_info partial_info; _partial_update_info w_partial_info; _partial_update_info r_partial_info; #define PARTIAL_INFO_QUEUE_SIZE 50 _partial_update_info partial_info_queue[PARTIAL_INFO_QUEUE_SIZE]; static int pr=0; static int pw=0; struct auo_fb_mach_info auo_mach_info = { //Video control 0 register, .vidcon0= S3C_VIDCON0_VIDOUT_RGB_IF | S3C_VIDCON0_PNRMODE_RGB_P | S3C_VIDCON0_CLKDIR_DIVIDED | S3C_VIDCON0_VCLKEN_ENABLE |S3C_VIDCON0_CLKSEL_F_HCLK, .vidcon1= S3C_VIDCON1_IHSYNC_INVERT | S3C_VIDCON1_IVSYNC_INVERT, //Video time control 0 register .vidtcon0= S3C_VIDTCON0_VBPD(V_BP-1) | S3C_VIDTCON0_VFPD(V_FP-1) | S3C_VIDTCON0_VSPW(V_SW-1), .vidtcon1= S3C_VIDTCON1_HBPD(H_BP-1) | S3C_VIDTCON1_HFPD(H_FP-1 ) | S3C_VIDTCON1_HSPW(H_SW-1), .vidtcon2= S3C_VIDTCON2_LINEVAL(V_RESOLUTION-1) | S3C_VIDTCON2_HOZVAL(H_RESOLUTION-1), // Window control 0 register, 4 bpp .wincon0= S3C_WINCONx_HAWSWP_ENABLE | S3C_WINCONx_BURSTLEN_4WORD | (2<<2), .wincon1= S3C_WINCONx_HAWSWP_ENABLE | S3C_WINCONx_BURSTLEN_4WORD | S3C_WINCONx_BPPMODE_F_16BPP_565 | S3C_WINCONx_BLD_PIX_PLANE | S3C_WINCONx_ALPHA_SEL_1, // 4word burst, 16bpp for OSD //Video Window 0, 1¡¦s position control register .vidosd0a= S3C_VIDOSDxA_OSD_LTX_F(0) | S3C_VIDOSDxA_OSD_LTY_F(0), .vidosd0b= S3C_VIDOSDxB_OSD_RBX_F(H_RESOLUTION-1) | S3C_VIDOSDxB_OSD_RBY_F(V_RESOLUTION-1), .vidosd1a= S3C_VIDOSDxA_OSD_LTX_F(0) | S3C_VIDOSDxA_OSD_LTY_F(0), .vidosd1b= S3C_VIDOSDxB_OSD_RBX_F(H_RESOLUTION_OSD-1) | S3C_VIDOSDxB_OSD_RBY_F(V_RESOLUTION_OSD-1), .vidosd1c= S3C_VIDOSDxC_ALPHA1_B(MAX_ALPHA_LEVEL) | S3C_VIDOSDxC_ALPHA1_G(MAX_ALPHA_LEVEL) |S3C_VIDOSDxC_ALPHA1_R(MAX_ALPHA_LEVEL), //Indicate the Video interrupt control register .vidintcon= S3C_VIDINTCON0_FRAMESEL0_VSYNC | S3C_VIDINTCON0_FRAMESEL1_NONE | S3C_VIDINTCON0_INTFRMEN_ENABLE | S3C_VIDINTCON0_INTEN_ENABLE, .width= H_RESOLUTION, .height= V_RESOLUTION, .xres= H_RESOLUTION, .yres= V_RESOLUTION, .xoffset= 0, .yoffset= 0, .xres_virtual = H_RESOLUTION, .yres_virtual = V_RESOLUTION, .osd_width= H_RESOLUTION_OSD, .osd_height= V_RESOLUTION_OSD, .osd_xres= H_RESOLUTION_OSD, .osd_yres= V_RESOLUTION_OSD, .osd_xres_virtual= H_RESOLUTION_OSD, .osd_yres_virtual= V_RESOLUTION_OSD, //Ivan .bpp= PIXEL_BPP16, .bytes_per_pixel= 2, /* #if defined (CONFIG_FB_BPP_8) .bpp= PIXEL_BPP8, .bytes_per_pixel= 1, #if defined(CONFIG_CPU_S3C2443) || defined(CONFIG_CPU_S3C2450) || defined(CONFIG_CPU_S3C2416) .wpalcon= W0PAL_24BIT, #elif defined(CONFIG_CPU_S3C6400) || defined(CONFIG_CPU_S3C6410) .wpalcon= W0PAL_16BIT, #endif #elif defined (CONFIG_FB_BPP_16) .bpp= PIXEL_BPP16, .bytes_per_pixel= 2, #elif defined (CONFIG_FB_BPP_24) .bpp= PIXEL_BPP24, .bytes_per_pixel= 4, #endif */ .pixclock= PIXEL_CLOCK, //Color key control register .w1keycon0= S3C_WxKEYCON0_KEYBLEN_DISABLE | S3C_WxKEYCON0_KEYEN_F_DISABLE | S3C_WxKEYCON0_DIRCON_MATCH_FG_IMAGE | S3C_WxKEYCON0_COMPKEY(0x0), .w1keycon1= S3C_WxKEYCON1_COLVAL(0xffffff), .w2keycon0= S3C_WxKEYCON0_KEYBLEN_DISABLE | S3C_WxKEYCON0_KEYEN_F_DISABLE | S3C_WxKEYCON0_DIRCON_MATCH_FG_IMAGE | S3C_WxKEYCON0_COMPKEY(0x0), .w2keycon1= S3C_WxKEYCON1_COLVAL(0xffffff), .w3keycon0= S3C_WxKEYCON0_KEYBLEN_DISABLE | S3C_WxKEYCON0_KEYEN_F_DISABLE | S3C_WxKEYCON0_DIRCON_MATCH_FG_IMAGE | S3C_WxKEYCON0_COMPKEY(0x0), .w3keycon1= S3C_WxKEYCON1_COLVAL(0xffffff), .w4keycon0= S3C_WxKEYCON0_KEYBLEN_DISABLE | S3C_WxKEYCON0_KEYEN_F_DISABLE | S3C_WxKEYCON0_DIRCON_MATCH_FG_IMAGE | S3C_WxKEYCON0_COMPKEY(0x0), .w4keycon1= S3C_WxKEYCON1_COLVAL(0xffffff), .hsync_len= H_SW, .vsync_len= V_SW, .left_margin= H_FP, .upper_margin= V_FP, .right_margin= H_BP, .lower_margin= V_BP, .sync= 0, .cmap_static= 1, }; struct semaphore vma_list_semaphore; struct fb_vma_list_entry { struct list_head list; struct vm_area_struct *vma; }; static unsigned long videomemorysize; struct page **videopages; static int numpages; LIST_HEAD(vma_list); static bool isInitial = false; static bool isReady = true; static bool update_ready = false; //timer static struct work_struct workq_panel_update; static struct timer_list panel_timer_qisda; static void panel_timer_handler_qisda(unsigned long data) { schedule_work(&workq_panel_update); } static int lock_auofb_entry(char *function_name); static void lock_auofb_exit(char *function_name); static bool auofb_update_queue_put(_partial_update_info put_region); static bool auofb_update_queue_get(_partial_update_info* get_region); static bool auofb_update_queue_is_empty(void); static bool auofb_update_queue_is_full(void); static void auofb_rotate_RGB565(unsigned short w, unsigned short h, unsigned short* src_data, unsigned short* dst_data); static void auofb_convert_RGB565(unsigned short w, unsigned short h, unsigned short* src_data, unsigned short* dst_data); static int update_display_thread(void *unused); static void start_update_display_thread(void); static void stop_update_display_thread(void); static panel_update_workqueue(struct work_struct *work); static void wake_update_display_thread(void); static int auo_fb_is_update_region_legal(void); #define LOCK_AUOFB_ENTRY() lock_auofb_entry((char *)__FUNCTION__) #define LOCK_AUOFB_EXIT() lock_auofb_exit((char *)__FUNCTION__) static int lock_auofb_entry(char *function_name) { int result = 0; //DPRINTK("%s(pid=%d) getting lock...\n", function_name, (int)sys_getpid()); // Did we get the lock? // if ( down_interruptible(&auofb_lock) ) //if ( down(&auofb_lock) ) { DPRINTK("%s(pid=%d) COULD NOT get lock...\n", function_name, (int)sys_getpid()); result = -ERESTARTSYS; } else { ; DPRINTK("%s(pid=%d) got lock...\n", function_name, (int)sys_getpid()); } // No, release it. // if ( result ) up(&auofb_lock); return ( result ); } static void lock_auofb_exit(char *function_name) { up(&auofb_lock); //DPRINTK("%s(pid=%d) released lock...\n", function_name, (int)sys_getpid()); } static bool auofb_update_queue_put(_partial_update_info put_region) { partial_info_queue[pw] = put_region; pw++; pw%=PARTIAL_INFO_QUEUE_SIZE; return true; } static bool auofb_update_queue_get(_partial_update_info* get_region) { *get_region = partial_info_queue[pr]; pr++; pr%=PARTIAL_INFO_QUEUE_SIZE; return true; } static bool auofb_update_queue_is_empty(void) { if(pr == pw) return true; return false; } static bool auofb_update_queue_is_full(void) { if(((pw+1)%PARTIAL_INFO_QUEUE_SIZE) == pr) return true; return false; } static void auofb_rotate_RGB565(unsigned short w, unsigned short h, unsigned short* src_data, unsigned short* dst_data) { int i,j; for(i=0; i< w; i++) { for(j=0; j< h; j++) { //printf("%d -%d\n", i * h + j, j * w + (w - i - 1)); dst_data[i * h + j] = src_data[j * w + (w - i - 1)]; } } } static void auofb_convert_RGB565(unsigned short w, unsigned short h, unsigned short* src_data, unsigned short* dst_data) { int i; unsigned short u16val; unsigned short* pu16TranslatePtr = dst_data; unsigned short* pu16ProcessPtr = src_data; for(i=0;i<(w*h*auo_mach_info.bytes_per_pixel/8);i++) { *pu16TranslatePtr = 0; // 1st pixel u16val = ((((*pu16ProcessPtr & 0xF800) >> auo_fb_rgb_16.red.offset)*77 + ((*pu16ProcessPtr & 0x07E0) >> (auo_fb_rgb_16.green.offset+1))*151 + ((*pu16ProcessPtr & 0x1F) >> auo_fb_rgb_16.blue.offset)*28)>>8 >>1); *pu16TranslatePtr = (*pu16TranslatePtr) | (u16val & 0x000F); // 2nd pixel u16val = ((((*(pu16ProcessPtr+1) & 0xF800) >> auo_fb_rgb_16.red.offset)*77 + ((*(pu16ProcessPtr+1) & 0x07E0) >> (auo_fb_rgb_16.green.offset+1))*151 + ((*(pu16ProcessPtr+1) & 0x1F) >> auo_fb_rgb_16.blue.offset)*28)>>8 >>1); *pu16TranslatePtr = (*pu16TranslatePtr) | ((u16val<<4) & 0x00F0); // 3rd pixel u16val = ((((*(pu16ProcessPtr+2) & 0xF800) >> auo_fb_rgb_16.red.offset)*77 + ((*(pu16ProcessPtr+2) & 0x07E0) >>(auo_fb_rgb_16.green.offset+1))*151 + ((*(pu16ProcessPtr+2) & 0x1F) >> auo_fb_rgb_16.blue.offset)*28)>>8>>1); *pu16TranslatePtr = (*pu16TranslatePtr) | ((u16val<<8) & 0x0F00); // 4th pixel u16val = ((((*(pu16ProcessPtr+3) & 0xF800) >> auo_fb_rgb_16.red.offset)*77 + ((*(pu16ProcessPtr+3) & 0x07E0) >> (auo_fb_rgb_16.green.offset+1))*151 + ((*(pu16ProcessPtr+3) & 0x1F) >> auo_fb_rgb_16.blue.offset)*28)>>8>>1); *pu16TranslatePtr = (*pu16TranslatePtr) | ((u16val<<12) & 0xF000); pu16TranslatePtr++; pu16ProcessPtr = pu16ProcessPtr+4; } } /* static void boot_progress_bar_draw_bar(void) { //u16boot_progress_bar_Data T_DISPLAY_FRAME stDisFrame; stDisFrame.u16EpaperCommand = AUO_EPAPER_CMD_PARTIALDISP; stDisFrame.tFrameRange.X = 199; stDisFrame.tFrameRange.Y = 92; stDisFrame.tFrameRange.W = 12; stDisFrame.tFrameRange.H = 420; Epaper_Set_Partial_Update_Mode(1); stDisFrame.pFrameData = u16boot_progress_bar_Data; if(is_Epaper_Write_Ready()) Epaper_Disp(stDisFrame); } */ static void boot_progress_bar_draw_percent(int percent) { T_DISPLAY_FRAME stDisFrame; int i; unsigned short progress_bar[BOOT_PROGRESS_BAR_W*BOOT_PROGRESS_BAR_H/4]; int line_bytes = BOOT_PROGRESS_BAR_W/4*2; memset((unsigned char*)progress_bar, 0xff, BOOT_PROGRESS_BAR_W*BOOT_PROGRESS_BAR_H/4*2); memset((unsigned char*)progress_bar+(BOOT_PROGRESS_BAR_H-(BOOT_PROGRESS_BAR_H*percent/100))*line_bytes, 0x0, (BOOT_PROGRESS_BAR_H*percent/100)*line_bytes); Epaper_Set_Partial_Update_Mode(1); stDisFrame.u16EpaperCommand = AUO_EPAPER_CMD_PARTIALDISP; stDisFrame.tFrameRange.X = BOOT_PROGRESS_BAR_X; stDisFrame.tFrameRange.Y = BOOT_PROGRESS_BAR_Y; stDisFrame.tFrameRange.W = BOOT_PROGRESS_BAR_W; stDisFrame.tFrameRange.H = BOOT_PROGRESS_BAR_H; stDisFrame.pFrameData = progress_bar; if(is_Epaper_Write_Ready()) { DPRINTK("\nEpaper Progress %d",percent); Epaper_Disp(stDisFrame); } } static int boot_progress_bar_thread(void *unused) { int thread_active = 1; int draw_count =0; msleep(500); //boot_progress_bar_draw_bar(); daemonize("Boot_progress_bar_udt"); allow_signal(SIGKILL); while ( thread_active ) { try_to_freeze(); //for freeze kernel_thread if ( !signal_pending(current) ) { printk("\nboot_progress_bar_thread"); boot_progress_bar_draw_percent(10+(draw_count*10)); draw_count++; if(draw_count ==10) { thread_active = 0; } interruptible_sleep_on_timeout(&boot_progress_bar_wq, BOOT_PROGRESS_BAR_DELAY_TIME); } else thread_active = 0; } complete_and_exit(&boot_progress_bar_thread_exited, 0); } static int update_display_thread(void *unused) { int thread_active = 1; int i=0; unsigned short* pu16ProcessPtr=NULL; unsigned short* pu16TranslatePtr=pu16Translatebuffer; unsigned short u16val; T_DISPLAY_FRAME stDisFrame; unsigned long count; unsigned long timeout_time = update_display_timeout; unsigned char* pu8Tmp_region = NULL; unsigned char* pu8Tmp_copy_ptr = NULL; int test_len=0; unsigned long tmp_clock; unsigned long total_clock; daemonize("AUOEINK_udt"); allow_signal(SIGKILL); #ifdef CONFIG_AUO_FB_AUTOUPDATE while ( thread_active ) { try_to_freeze(); //for freeze kernel_thread if ( !signal_pending(current) ) { if ( 0 == LOCK_AUOFB_ENTRY() ) { pu16ProcessPtr = NULL; pu16TranslatePtr = pu16Translatebuffer; //if(update_ready) while(!auofb_update_queue_is_empty()) { DPRINTK("AUO EINK time start, jiffies: %lu, HZ: %lu\n", jiffies, HZ); total_clock = tmp_clock = jiffies; auofb_update_queue_get(&r_partial_info); Epaper_Set_Partial_Update_Mode(r_partial_info.mode); #ifdef EPD_HW_ROTATE #ifdef EPD_HW_ROTATE_NO_MODE4 if((r_partial_info.mode == PARTIAL_DSP_MODE_4) || (r_partial_info.mode == PARTIAL_DSP_MODE_4_W)) { if( (u16PrevMode != PARTIAL_DSP_MODE_4) && (u16PrevMode != PARTIAL_DSP_MODE_4_W) ) { if(is_Epaper_Write_Ready()) Epaper_Init(AUO_EPAPER_PHYSICAL_H_RESOLUTION, AUO_EPAPER_PHYSICAL_V_RESOLUTION, 0, 0, 0, 0, 0, 0); } //check if the updated region is valid if( (r_partial_info.w == auo_mach_info.xres_virtual) && (r_partial_info.h == auo_mach_info.yres_virtual)) { //rotate auofb_rotate_RGB565(auo_mach_info.xres_virtual, auo_mach_info.yres_virtual, (unsigned short*) pu8Framebuffer, (unsigned short*)pu8RotateBuffer); } else { pu8Tmp_region = vmalloc(r_partial_info.w * 2 * r_partial_info.h); // *2 --> unsigned short DPRINTK("\nAlloc tmp region len 1 =%d\n",r_partial_info.w * 2 * r_partial_info.h); pu8Tmp_copy_ptr = pu8Framebuffer + (H_RESOLUTION * 2 * (r_partial_info.y) + ((r_partial_info.x) * 2)); test_len=0; for(i=0;i unsigned short DPRINTK("\nAlloc tmp region len 1 =%d\n",r_partial_info.w * 2 * r_partial_info.h); pu8Tmp_copy_ptr = pu8Framebuffer + (H_RESOLUTION * 2 * (r_partial_info.y) + ((r_partial_info.x) * 2)); test_len=0; for(i=0;i unsigned short DPRINTK("\nAlloc tmp region len 1 =%d\n",r_partial_info.w * 2 * r_partial_info.h); pu8Tmp_copy_ptr = pu8Framebuffer + (H_RESOLUTION * 2 * (r_partial_info.y) + ((r_partial_info.x) * 2)); test_len=0; for(i=0;i (boot_progress_bar_pid = kernel_thread(boot_progress_bar_thread, NULL, CLONE_KERNEL)) ) boot_progress_bar_pid = 0; } static void start_update_display_thread(void) { init_waitqueue_head(&update_display_wq); if ( 0 > (update_display_pid = kernel_thread(update_display_thread, NULL, CLONE_KERNEL)) ) update_display_pid = 0; isInitial = true; } static void stop_boot_progress_bar_thread(void) { if ( 0 < boot_progress_bar_pid ) if ( 0 == kill_proc(boot_progress_bar_pid, SIGKILL, 1) ) wait_for_completion(&boot_progress_bar_thread_exited); } static void stop_update_display_thread(void) { if ( 0 < update_display_pid ) if ( 0 == kill_proc(update_display_pid, SIGKILL, 1) ) wait_for_completion(&update_display_thread_exited); } static panel_update_workqueue(struct work_struct *work) { if ( 0 == LOCK_AUOFB_ENTRY() ) { if(is_Epaper_Write_Ready()) { DPRINTK("\n!!! Time's up!\n"); panel_timer_qisda.expires = jiffies + (10*HZ)/10; //update_ready = true; wake_up(&update_display_wq); } LOCK_AUOFB_EXIT(); } //mod_timer(&panel_timer_qisda,panel_timer_qisda.expires); //del_timer(&touch_iic_timer_qisda); } static void wake_update_display_thread(void) { if ( 0 == LOCK_AUOFB_ENTRY() ) { if(is_Epaper_Write_Ready()) { update_ready = true; wake_up(&update_display_wq); } LOCK_AUOFB_EXIT(); } } /** * auofb_open - Optional function. Called when the framebuffer is * first accessed. * @info: frame buffer structure that represents a single frame buffer * @user: tell us if the userland (value=1) or the console is accessing * the framebuffer. * * This function is the first function called in the framebuffer api. * Usually you don't need to provide this function. The case where it * is used is to change from a text mode hardware state to a graphics * mode state. * * Returns negative errno on error, or zero on success. */ static int auofb_open(const struct fb_info *info, int user) { return 0; } /** * auofb_release - Optional function. Called when the framebuffer * device is closed. * @info: frame buffer structure that represents a single frame buffer * @user: tell us if the userland (value=1) or the console is accessing * the framebuffer. * * Thus function is called when we close /dev/fb or the framebuffer * console system is released. Usually you don't need this function. * The case where it is usually used is to go from a graphics state * to a text mode state. * * Returns negative errno on error, or zero on success. */ static int auofb_release(const struct fb_info *info, int user) { return 0; } /** * auofb_check_var - Optional function. Validates a var passed in. * @var: frame buffer variable screen structure * @info: frame buffer structure that represents a single frame buffer * * Checks to see if the hardware supports the state requested by * var passed in. This function does not alter the hardware state!!! * This means the data stored in struct fb_info and struct auo_par do * not change. This includes the var inside of struct fb_info. * Do NOT change these. This function can be called on its own if we * intent to only test a mode and not actually set it. The stuff in * modedb.c is a example of this. If the var passed in is slightly * off by what the hardware can support then we alter the var PASSED in * to what we can do. * * For values that are off, this function must round them _up_ to the * next value that is supported by the hardware. If the value is * greater than the highest value supported by the hardware, then this * function must return -EINVAL. * * Exception to the above rule: Some drivers have a fixed mode, ie, * the hardware is already set at boot up, and cannot be changed. In * this case, it is more acceptable that this function just return * a copy of the currently working var (info->var). Better is to not * implement this function, as the upper layer will do the copying * of the current var for you. * * Note: This is the only function where the contents of var can be * freely adjusted after the driver has been registered. If you find * that you have code outside of this function that alters the content * of var, then you are doing something wrong. Note also that the * contents of info->var must be left untouched at all times after * driver registration. * * Returns negative errno on error, or zero on success. */ static int auofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { DPRINTK("check_var(var=%p, info=%p)\n", var, info); switch (var->bits_per_pixel) { case 4: var->red = auo_fb_rgb_4.red; var->green = auo_fb_rgb_4.green; var->blue = auo_fb_rgb_4.blue; var->transp = auo_fb_rgb_4.transp; break; case 8: var->red = auo_fb_rgb_8.red; var->green = auo_fb_rgb_8.green; var->blue = auo_fb_rgb_8.blue; var->transp = auo_fb_rgb_8.transp; break; case 16: var->red = auo_fb_rgb_16.red; var->green = auo_fb_rgb_16.green; var->blue = auo_fb_rgb_16.blue; var->transp = auo_fb_rgb_16.transp; break; case 24: var->red = auo_fb_rgb_24.red; var->green = auo_fb_rgb_24.green; var->blue = auo_fb_rgb_24.blue; var->transp = auo_fb_rgb_24.transp; break; case 32: var->red = auo_fb_rgb_32.red; var->green = auo_fb_rgb_32.green; var->blue = auo_fb_rgb_32.blue; var->transp = auo_fb_rgb_32.transp; break; } return 0; } void auo_fb_activate_var(struct auo_fb_info *fbi, struct fb_var_screeninfo *var) { DPRINTK("%s: var->bpp = %d\n", __FUNCTION__, var->bits_per_pixel); switch (var->bits_per_pixel) { case 4: auo_mach_info.wincon0= S3C_WINCONx_HAWSWP_ENABLE | S3C_WINCONx_BURSTLEN_4WORD | S3C_WINCONx_BPPMODE_F_16BPP_565; // 4word burst, 16bpp, auo_mach_info.wincon1= S3C_WINCONx_HAWSWP_ENABLE | S3C_WINCONx_BURSTLEN_4WORD | S3C_WINCONx_BPPMODE_F_16BPP_565 | S3C_WINCONx_BLD_PIX_PLANE | S3C_WINCONx_ALPHA_SEL_1; // auo_mach_info.bpp= PIXEL_BPP4; auo_mach_info.bytes_per_pixel= 1; break; case 8: auo_mach_info.wincon0= S3C_WINCONx_BYTSWP_ENABLE | S3C_WINCONx_BURSTLEN_4WORD | S3C_WINCONx_BPPMODE_F_8BPP_PAL; // 4word burst, 8bpp-palletized, auo_mach_info.wincon1= S3C_WINCONx_HAWSWP_ENABLE | S3C_WINCONx_BURSTLEN_4WORD | S3C_WINCONx_BPPMODE_F_16BPP_565 | S3C_WINCONx_BLD_PIX_PLANE | S3C_WINCONx_ALPHA_SEL_1; // 4word burst, 16bpp for OSD auo_mach_info.bpp= PIXEL_BPP8; auo_mach_info.bytes_per_pixel= 1; auo_mach_info.wpalcon= S3C_WPALCON_W0PAL_24BIT; break; case 16: auo_mach_info.wincon0= S3C_WINCONx_HAWSWP_ENABLE | S3C_WINCONx_BURSTLEN_4WORD | S3C_WINCONx_BPPMODE_F_16BPP_565; // 4word burst, 16bpp, auo_mach_info.wincon1= S3C_WINCONx_HAWSWP_ENABLE | S3C_WINCONx_BURSTLEN_4WORD | S3C_WINCONx_BPPMODE_F_16BPP_565 | S3C_WINCONx_BLD_PIX_PLANE | S3C_WINCONx_ALPHA_SEL_1; // auo_mach_info.bpp= PIXEL_BPP16; auo_mach_info.bytes_per_pixel= 2; break; case 24: auo_mach_info.wincon0= S3C_WINCONx_HAWSWP_DISABLE | S3C_WINCONx_BURSTLEN_16WORD | S3C_WINCONx_BPPMODE_F_24BPP_888; // 4word burst, 24bpp,, auo_mach_info.wincon1= S3C_WINCONx_HAWSWP_DISABLE | S3C_WINCONx_BURSTLEN_16WORD | S3C_WINCONx_BPPMODE_F_24BPP_888 | S3C_WINCONx_BLD_PIX_PLANE | S3C_WINCONx_ALPHA_SEL_1; // 4word burst, 24bpp for OSD auo_mach_info.bpp= PIXEL_BPP24; auo_mach_info.bytes_per_pixel= 4; break; case 32: auo_mach_info.bytes_per_pixel= 4; break; } #if 0 /* write new registers */ __raw_writel(auo_mach_info.wincon0, S3C_WINCON0); __raw_writel(auo_mach_info.wincon1, S3C_WINCON1); __raw_writel(auo_mach_info.wpalcon, S3C_WPALCON); //__raw_writel(mach_info.wincon0|S3C_WINCONx_ENWIN_F_ENABLE|S3C_WINCONx_BUFAUTOEN_ENABLE, S3C_WINCON0); /* Double buffer auto enable bit */ __raw_writel(auo_mach_info.wincon0|S3C_WINCONx_ENWIN_F_ENABLE, S3C_WINCON0); __raw_writel(auo_mach_info.vidcon0|S3C_VIDCON0_ENVID_ENABLE|S3C_VIDCON0_ENVID_F_ENABLE, S3C_VIDCON0); #endif } /** * auofb_set_par - Optional function. Alters the hardware state. * @info: frame buffer structure that represents a single frame buffer * * Using the fb_var_screeninfo in fb_info we set the resolution of the * this particular framebuffer. This function alters the par AND the * fb_fix_screeninfo stored in fb_info. It doesn't not alter var in * fb_info since we are using that data. This means we depend on the * data in var inside fb_info to be supported by the hardware. * * This function is also used to recover/restore the hardware to a * known working state. * * auofb_check_var is always called before auofb_set_par to ensure that * the contents of var is always valid. * * Again if you can't change the resolution you don't need this function. * * However, even if your hardware does not support mode changing, * a set_par might be needed to at least initialize the hardware to * a known working state, especially if it came back from another * process that also modifies the same hardware, such as X. * * If this is the case, a combination such as the following should work: * * static int auofb_check_var(struct fb_var_screeninfo *var, * struct fb_info *info) * { * *var = info->var; * return 0; * } * * static int auofb_set_par(struct fb_info *info) * { * init your hardware here * } * * Returns negative errno on error, or zero on success. */ static int auofb_set_par(struct fb_info *info) { struct auo_fb_info *fbi = (struct auo_fb_info *)info; struct fb_var_screeninfo *var = &info->var; if (var->bits_per_pixel == 16) fbi->fb.fix.visual = FB_VISUAL_TRUECOLOR; else if (var->bits_per_pixel == 32) fbi->fb.fix.visual = FB_VISUAL_TRUECOLOR; else fbi->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; fbi->fb.fix.line_length = var->width * auo_mach_info.bytes_per_pixel; /* activate this new configuration */ auo_fb_activate_var(fbi, var); return 0; } /** * auofb_setcolreg - Optional function. Sets a color register. * @regno: Which register in the CLUT we are programming * @red: The red value which can be up to 16 bits wide * @green: The green value which can be up to 16 bits wide * @blue: The blue value which can be up to 16 bits wide. * @transp: If supported, the alpha value which can be up to 16 bits wide. * @info: frame buffer info structure * * Set a single color register. The values supplied have a 16 bit * magnitude which needs to be scaled in this function for the hardware. * Things to take into consideration are how many color registers, if * any, are supported with the current color visual. With truecolor mode * no color palettes are supported. Here a pseudo palette is created * which we store the value in pseudo_palette in struct fb_info. For * pseudocolor mode we have a limited color palette. To deal with this * we can program what color is displayed for a particular pixel value. * DirectColor is similar in that we can program each color field. If * we have a static colormap we don't need to implement this function. * * Returns negative errno on error, or zero on success. */ static int auofb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, const struct fb_info *info) { struct auo_fb_info *fbi = (struct auo_fb_info *)info; unsigned int val; switch (fbi->fb.fix.visual) { case FB_VISUAL_TRUECOLOR: /* true-colour, use pseuo-palette */ if (regno < 16) { u32 *pal = fbi->fb.pseudo_palette; /* val = chan_to_field(red, fbi->fb.var.red); val |= chan_to_field(green, fbi->fb.var.green); val |= chan_to_field(blue, fbi->fb.var.blue); */ pal[regno] = val; } break; case FB_VISUAL_PSEUDOCOLOR: if (regno < 256) { /* currently assume RGB 8-8-8 mode -- for SONY */ val = ((red << 8) & 0xff0000); val |= ((green >> 0) & 0xff00); val |= ((blue >> 8) & 0xff); DPRINTK("index = %d, val = 0x%8X\n", regno, val); //schedule_palette_update(fbi, regno, val); } break; default: return 1; /* unknown type */ } return 0; } /** * auofb_pan_display - NOT a required function. Pans the display. * @var: frame buffer variable screen structure * @info: frame buffer structure that represents a single frame buffer * * Pan (or wrap, depending on the `vmode' field) the display using the * `xoffset' and `yoffset' fields of the `var' structure. * If the values don't fit, return -EINVAL. * * Returns negative errno on error, or zero on success. */ static int auofb_pan_display(struct fb_var_screeninfo *var, const struct fb_info *info) { /* * If your hardware does not support panning, _do_ _not_ implement this * function. Creating a dummy function will just confuse user apps. */ /* * Note that even if this function is fully functional, a setting of * 0 in both xpanstep and ypanstep means that this function will never * get called. */ /* ... */ return 0; } /** * auofb_blank - NOT a required function. Blanks the display. * @blank_mode: the blank mode we want. * @info: frame buffer structure that represents a single frame buffer * * Blank the screen if blank_mode != FB_BLANK_UNBLANK, else unblank. * Return 0 if blanking succeeded, != 0 if un-/blanking failed due to * e.g. a video mode which doesn't support it. * * Implements VESA suspend and powerdown modes on hardware that supports * disabling hsync/vsync: * * FB_BLANK_NORMAL = display is blanked, syncs are on. * FB_BLANK_HSYNC_SUSPEND = hsync off * FB_BLANK_VSYNC_SUSPEND = vsync off * FB_BLANK_POWERDOWN = hsync and vsync off * * If implementing this function, at least support FB_BLANK_UNBLANK. * Return !0 for any modes that are unimplemented. * */ static int auofb_blank(int blank_mode, const struct fb_info *info) { /* ... */ return 0; } /* ------------ Accelerated Functions --------------------- */ /* * We provide our own functions if we have hardware acceleration * or non packed pixel format layouts. If we have no hardware * acceleration, we can use a generic unaccelerated function. If using * a pack pixel format just use the functions in cfb_*.c. Each file * has one of the three different accel functions we support. */ /** * auofb_fillrect - REQUIRED function. Can use generic routines if * non acclerated hardware and packed pixel based. * Draws a rectangle on the screen. * * @info: frame buffer structure that represents a single frame buffer * @region: The structure representing the rectangular region we * wish to draw to. * * This drawing operation places/removes a retangle on the screen * depending on the rastering operation with the value of color which * is in the current color depth format. */ void auofb_fillrect(struct fb_info *p, const struct fb_fillrect *region) { /* Meaning of struct fb_fillrect * * @dx: The x and y corrdinates of the upper left hand corner of the * @dy: area we want to draw to. * @width: How wide the rectangle is we want to draw. * @height: How tall the rectangle is we want to draw. * @color: The color to fill in the rectangle with. * @rop: The raster operation. We can draw the rectangle with a COPY * of XOR which provides erasing effect. */ } /** * auofb_copyarea - REQUIRED function. Can use generic routines if * non acclerated hardware and packed pixel based. * Copies one area of the screen to another area. * * @info: frame buffer structure that represents a single frame buffer * @area: Structure providing the data to copy the framebuffer contents * from one region to another. * * This drawing operation copies a rectangular area from one area of the * screen to another area. */ void auofb_copyarea(struct fb_info *p, const struct fb_copyarea *area) { /* * @dx: The x and y coordinates of the upper left hand corner of the * @dy: destination area on the screen. * @width: How wide the rectangle is we want to copy. * @height: How tall the rectangle is we want to copy. * @sx: The x and y coordinates of the upper left hand corner of the * @sy: source area on the screen. */ } /** * auofb_imageblit - REQUIRED function. Can use generic routines if * non acclerated hardware and packed pixel based. * Copies a image from system memory to the screen. * * @info: frame buffer structure that represents a single frame buffer * @image: structure defining the image. * * This drawing operation draws a image on the screen. It can be a * mono image (needed for font handling) or a color image (needed for * tux). */ void auofb_imageblit(struct fb_info *p, const struct fb_image *image) { /* * @dx: The x and y coordinates of the upper left hand corner of the * @dy: destination area to place the image on the screen. * @width: How wide the image is we want to copy. * @height: How tall the image is we want to copy. * @fg_color: For mono bitmap images this is color data for * @bg_color: the foreground and background of the image to * write directly to the frmaebuffer. * @depth: How many bits represent a single pixel for this image. * @data: The actual data used to construct the image on the display. * @cmap: The colormap used for color images. */ /* * The generic function, cfb_imageblit, expects that the bitmap scanlines are * padded to the next byte. Most hardware accelerators may require padding to * the next u16 or the next u32. If that is the case, the driver can specify * this by setting info->pixmap.scan_align = 2 or 4. See a more * comprehensive description of the pixmap below. */ } /** * auofb_cursor - OPTIONAL. If your hardware lacks support * for a cursor, leave this field NULL. * * @info: frame buffer structure that represents a single frame buffer * @cursor: structure defining the cursor to draw. * * This operation is used to set or alter the properities of the * cursor. * * Returns negative errno on error, or zero on success. */ #if 0 int auofb_cursor(struct fb_info *info, struct fb_cursor *cursor) { /* * @set: Which fields we are altering in struct fb_cursor * @enable: Disable or enable the cursor * @rop: The bit operation we want to do. * @mask: This is the cursor mask bitmap. * @dest: A image of the area we are going to display the cursor. * Used internally by the driver. * @hot: The hot spot. * @image: The actual data for the cursor image. * * NOTES ON FLAGS (cursor->set): * * FB_CUR_SETIMAGE - the cursor image has changed (cursor->image.data) * FB_CUR_SETPOS - the cursor position has changed (cursor->image.dx|dy) * FB_CUR_SETHOT - the cursor hot spot has changed (cursor->hot.dx|dy) * FB_CUR_SETCMAP - the cursor colors has changed (cursor->fg_color|bg_color) * FB_CUR_SETSHAPE - the cursor bitmask has changed (cursor->mask) * FB_CUR_SETSIZE - the cursor size has changed (cursor->width|height) * FB_CUR_SETALL - everything has changed * * NOTES ON ROPs (cursor->rop, Raster Operation) * * ROP_XOR - cursor->image.data XOR cursor->mask * ROP_COPY - curosr->image.data AND cursor->mask * * OTHER NOTES: * * - fbcon only supports a 2-color cursor (cursor->image.depth = 1) * - The fb_cursor structure, @cursor, _will_ always contain valid * fields, whether any particular bitfields in cursor->set is set * or not. */ } /** * auofb_rotate - NOT a required function. If your hardware * supports rotation the whole screen then * you would provide a hook for this. * * @info: frame buffer structure that represents a single frame buffer * @angle: The angle we rotate the screen. * * This operation is used to set or alter the properities of the * cursor. */ void auofb_rotate(struct fb_info *info, int angle) { /* Will be deprecated */ } /** * auofb_poll - NOT a required function. The purpose of this * function is to provide a way for some process * to wait until a specific hardware event occurs * for the framebuffer device. * * @info: frame buffer structure that represents a single frame buffer * @wait: poll table where we store process that await a event. */ void auofb_poll(struct fb_info *info, poll_table *wait) { } /** * auofb_sync - NOT a required function. Normally the accel engine * for a graphics card take a specific amount of time. * Often we have to wait for the accelerator to finish * its operation before we can write to the framebuffer * so we can have consistent display output. * * @info: frame buffer structure that represents a single frame buffer * * If the driver has implemented its own hardware-based drawing function, * implementing this function is highly recommended. */ void auofb_sync(struct fb_info *info) { } #endif /* * Initialization */ static int add_vma(struct vm_area_struct *vma) { struct fb_vma_list_entry *list_entry; DPRINTK("\n@@@@@@@@@add_vma"); list_entry = kmalloc(sizeof(struct fb_vma_list_entry), GFP_KERNEL); list_entry->vma = vma; down_interruptible(&vma_list_semaphore); list_add_tail((struct list_head *)list_entry, &vma_list); up(&vma_list_semaphore); return 0; } static struct fb_vma_list_entry *find_fb_vma_entry(struct vm_area_struct *vma) { struct list_head *ptr; struct fb_vma_list_entry *entry; DPRINTK("\n@@@@@@@@@find_fb_vma_entry"); for (ptr = vma_list.next; ptr != &vma_list; ptr = ptr->next) { entry = list_entry(ptr, struct fb_vma_list_entry, list); if (entry->vma == vma) { return entry; } } return NULL; } static int remove_vma(struct vm_area_struct *vma) { struct fb_vma_list_entry *entry; DPRINTK("\n@@@@@@@@@remove_vma"); down_interruptible(&vma_list_semaphore); entry = find_fb_vma_entry(vma); if (entry != NULL) { list_del((struct list_head *) entry); kfree(entry); } up(&vma_list_semaphore); return 0; } void auo_fb_vma_open(struct vm_area_struct *vma) { DPRINTK("\n@@@@@@@@@auo_fb_vma_open"); add_vma(vma); } void auo_fb_vma_close(struct vm_area_struct *vma) { DPRINTK("\n@@@@@@@@@auo_fb_vma_close"); remove_vma(vma); } struct page *auo_fb_vma_nopage( struct vm_area_struct *vma, unsigned long address, int *type) { unsigned long offset; struct page *page = NOPAGE_SIGBUS; //DPRINTK("\n@@@@@@@@@auo_fb_vma_nopage"); offset = address - vma->vm_start + (vma->vm_pgoff << PAGE_SHIFT); if (offset > videomemorysize) { return page; } page = videopages[offset >> PAGE_SHIFT]; get_page(page); return page; } static struct vm_operations_struct auo_fb_vma_ops = { open: auo_fb_vma_open, close: auo_fb_vma_close, nopage: auo_fb_vma_nopage, }; int auo_fb_mmap( //struct fb_info *info, struct file *file, struct vm_area_struct *vma) { DPRINTK("\n@@@@@@@@@auo_fb_mmap"); DPRINTK("\n@@@@@@@@@@mmap size=%d\n", vma->vm_end - vma->vm_start); vma->vm_ops = &auo_fb_vma_ops; vma->vm_flags |= VM_RESERVED; auo_fb_vma_open(vma); /* unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; if(offset >= __pa(high_memory) || (file->f_flags & O_SYNC)) vma->vm_flags |= VM_IO; vma->vm_flags |= VM_RESERVED; DPRINTK("\noffset=%d",offset); offset += S3C24XX_PA_LCD; if(remap_pfn_range(vma, vma->vm_start, offset >> PAGE_SHIFT, vma->vm_end - vma->vm_start, vma->vm_page_prot)) return -EAGAIN; */ return 0; } static int auo_fb_is_update_region_legal(void) { #ifdef EPD_HW_ROTATE #ifdef EPD_HW_ROTATE_NO_MODE4 if((w_partial_info.mode == PARTIAL_DSP_MODE_4) || (w_partial_info.mode == PARTIAL_DSP_MODE_4_W)) { if( (w_partial_info.x > (H_RESOLUTION-1)) || (w_partial_info.y > (V_RESOLUTION-1)) || (w_partial_info.w == 0) || (w_partial_info.h == 0) || (w_partial_info.w > H_RESOLUTION) || (w_partial_info.h > V_RESOLUTION)) return -EINVAL; //fill data to legal region if((w_partial_info.x + w_partial_info.w) > H_RESOLUTION) w_partial_info.w = H_RESOLUTION - w_partial_info.x; if((w_partial_info.y + w_partial_info.h) > V_RESOLUTION) w_partial_info.h = V_RESOLUTION - w_partial_info.y; if(((w_partial_info.y+1) % 2)==0) //In EPD view, X is not odd { DPRINTK("\nw_partial_info.y=%d\n",w_partial_info.y); w_partial_info.y--; w_partial_info.h++; //because w_partial_info.y-- } if(w_partial_info.h < 12) w_partial_info.h = 12; if((w_partial_info.h % 4) != 0) //In EPD view, w is not times of 4 { DPRINTK("\nw_partial_info.h=%d\n",w_partial_info.h); int tmp_offset = 4 - w_partial_info.h%4; w_partial_info.h = w_partial_info.h + tmp_offset; } if(((w_partial_info.y + 1) + w_partial_info.h)> (V_RESOLUTION+1)) { w_partial_info.y = V_RESOLUTION - w_partial_info.h ; //w_partial_info.h = V_RESOLUTION; //w_partial_info.y = 0; } if(w_partial_info.w < 2) w_partial_info.w = 2; if((((H_RESOLUTION - (w_partial_info.x) - w_partial_info.w) +1) % 2)==0) //In EPD view, Y is not odd { //w_partial_info.x--; w_partial_info.w = w_partial_info.w+1; } if((w_partial_info.w % 2) != 0) //In EPD view, h is not times of 2 { DPRINTK("\nw_partial_info.w=%d\n",w_partial_info.w); int tmp_offset = 2 - w_partial_info.w%2; w_partial_info.w = w_partial_info.w + tmp_offset; w_partial_info.x = w_partial_info.x - tmp_offset; } if((((H_RESOLUTION - (w_partial_info.x) - w_partial_info.w) +1) + w_partial_info.w)> (H_RESOLUTION+1)) { w_partial_info.x = H_RESOLUTION - w_partial_info.w ; } //check (x,y,w,h) again if(((w_partial_info.y + 1) < 1) || (((H_RESOLUTION - (w_partial_info.x) - w_partial_info.w) +1) < 1) || (w_partial_info.h < 12) || (w_partial_info.w < 2) || ((w_partial_info.y + 1 + w_partial_info.h)>(V_RESOLUTION+1)) || (((H_RESOLUTION - (w_partial_info.x) - w_partial_info.w) +1 + w_partial_info.w)>(H_RESOLUTION+1)) || (((w_partial_info.y+1) % 2)==0) || ((((H_RESOLUTION - (w_partial_info.x) - w_partial_info.w) +1) % 2)==0) || ((w_partial_info.h % 4) != 0) || ((w_partial_info.w % 2) != 0) ) { printk("\nAUOFB ERROR: (X,Y,W,L)=(%d,%d,%d,%d)",w_partial_info.y + 1, (H_RESOLUTION - (w_partial_info.x) - w_partial_info.w) +1, w_partial_info.h, w_partial_info.w); return -EFAULT; } return 0; } #endif //check (X,Y,W,H) first time if( (w_partial_info.x > (H_RESOLUTION-1)) || (w_partial_info.y > (V_RESOLUTION-1)) || (w_partial_info.w == 0) || (w_partial_info.h == 0) || (w_partial_info.w > H_RESOLUTION) || (w_partial_info.h > V_RESOLUTION)) return -EINVAL; //fill data to legal region if((w_partial_info.x + w_partial_info.w) > H_RESOLUTION) w_partial_info.w = H_RESOLUTION - w_partial_info.x; if((w_partial_info.y + w_partial_info.h) > V_RESOLUTION) w_partial_info.h = V_RESOLUTION - w_partial_info.y; if(((w_partial_info.x+1) % 2)==0) //X is not odd { DPRINTK("\nw_partial_info.x=%d\n",w_partial_info.x); w_partial_info.x--; w_partial_info.w++; //because w_partial_info.x-- } if(w_partial_info.w < 12) w_partial_info.w = 12; if((w_partial_info.w % 4) != 0) //w is not times of 4 { DPRINTK("\nw_partial_info.w=%d\n",w_partial_info.w); int tmp_offset = 4 - w_partial_info.w%4; w_partial_info.w = w_partial_info.w + tmp_offset; } if(((w_partial_info.x + 1) + w_partial_info.w)> (H_RESOLUTION+1)) { w_partial_info.x = H_RESOLUTION - w_partial_info.w ; } if(w_partial_info.h < 2) w_partial_info.h = 2; if(((w_partial_info.y+1) % 2)==0) //Y is not odd { if(w_partial_info.y > 3) { w_partial_info.y = w_partial_info.y -3; w_partial_info.h = w_partial_info.h+3; } else { w_partial_info.y--; w_partial_info.h = w_partial_info.h+1; } } if((w_partial_info.h % 2) != 0) //h is not times of 2 { DPRINTK("\nw_partial_info.h=%d\n",w_partial_info.h); int tmp_offset = 2 - w_partial_info.h%2; w_partial_info.h = w_partial_info.h + tmp_offset; } if(((w_partial_info.y + 1) + w_partial_info.h)> (V_RESOLUTION+1)) { w_partial_info.y = V_RESOLUTION - w_partial_info.h ; } //check (x,y,w,h) again if(((w_partial_info.x + 1) < 1) || ((w_partial_info.y +1) < 1) || (w_partial_info.w < 12) || (w_partial_info.h < 2) || ((w_partial_info.x + 1 + w_partial_info.w)>(H_RESOLUTION+1)) || ((w_partial_info.y +1 + w_partial_info.h)>(V_RESOLUTION+1)) || (((w_partial_info.x+1) % 2)==0) || (((w_partial_info.y +1) % 2)==0) || ((w_partial_info.w % 4) != 0) || ((w_partial_info.h % 2) != 0) ) { printk("\nAUOFB ERROR: (X,Y,W,L)=(%d,%d,%d,%d)",w_partial_info.x + 1, w_partial_info.y + 1, w_partial_info.w, w_partial_info.h); return -EFAULT; } #else #ifdef AUOFB_ROTATE //check (X,Y,W,H) first time if( (w_partial_info.x > (H_RESOLUTION-1)) || (w_partial_info.y > (V_RESOLUTION-1)) || (w_partial_info.w == 0) || (w_partial_info.h == 0) || (w_partial_info.w > H_RESOLUTION) || (w_partial_info.h > V_RESOLUTION)) return -EINVAL; //fill data to legal region if((w_partial_info.x + w_partial_info.w) > H_RESOLUTION) w_partial_info.w = H_RESOLUTION - w_partial_info.x; if((w_partial_info.y + w_partial_info.h) > V_RESOLUTION) w_partial_info.h = V_RESOLUTION - w_partial_info.y; if(((w_partial_info.y+1) % 2)==0) //In EPD view, X is not odd { DPRINTK("\nw_partial_info.y=%d\n",w_partial_info.y); w_partial_info.y--; w_partial_info.h++; //because w_partial_info.y-- } if(w_partial_info.h < 12) w_partial_info.h = 12; if((w_partial_info.h % 4) != 0) //In EPD view, w is not times of 4 { DPRINTK("\nw_partial_info.h=%d\n",w_partial_info.h); int tmp_offset = 4 - w_partial_info.h%4; w_partial_info.h = w_partial_info.h + tmp_offset; } if(((w_partial_info.y + 1) + w_partial_info.h)> (V_RESOLUTION+1)) { w_partial_info.y = V_RESOLUTION - w_partial_info.h ; //w_partial_info.h = V_RESOLUTION; //w_partial_info.y = 0; } if(w_partial_info.w < 2) w_partial_info.w = 2; if((((H_RESOLUTION - (w_partial_info.x) - w_partial_info.w) +1) % 2)==0) //In EPD view, Y is not odd { //w_partial_info.x--; w_partial_info.w = w_partial_info.w+1; } if((w_partial_info.w % 2) != 0) //In EPD view, h is not times of 2 { DPRINTK("\nw_partial_info.w=%d\n",w_partial_info.w); int tmp_offset = 2 - w_partial_info.w%2; w_partial_info.w = w_partial_info.w + tmp_offset; w_partial_info.x = w_partial_info.x - tmp_offset; } if((((H_RESOLUTION - (w_partial_info.x) - w_partial_info.w) +1) + w_partial_info.w)> (H_RESOLUTION+1)) { w_partial_info.x = H_RESOLUTION - w_partial_info.w ; } //check (x,y,w,h) again if(((w_partial_info.y + 1) < 1) || (((H_RESOLUTION - (w_partial_info.x) - w_partial_info.w) +1) < 1) || (w_partial_info.h < 12) || (w_partial_info.w < 2) || ((w_partial_info.y + 1 + w_partial_info.h)>(V_RESOLUTION+1)) || (((H_RESOLUTION - (w_partial_info.x) - w_partial_info.w) +1 + w_partial_info.w)>(H_RESOLUTION+1)) || (((w_partial_info.y+1) % 2)==0) || ((((H_RESOLUTION - (w_partial_info.x) - w_partial_info.w) +1) % 2)==0) || ((w_partial_info.h % 4) != 0) || ((w_partial_info.w % 2) != 0) ) { printk("\nAUOFB ERROR: (X,Y,W,L)=(%d,%d,%d,%d)",w_partial_info.y + 1, (H_RESOLUTION - (w_partial_info.x) - w_partial_info.w) +1, w_partial_info.h, w_partial_info.w); return -EFAULT; } #endif //#ifdef AUOFB_ROTATE #endif //#ifdef EPD_HW_ROTATE return 0; } int auo_fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { struct auo_fb_info *fbi = container_of(info, struct auo_fb_info, fb); struct fb_var_screeninfo *var= &fbi->fb.var; void __user *argp = (void __user *)arg; struct vm_area_struct *tvma; struct page *tpage; u_int virt_addr, phys_addr, offset; struct mm_struct *mm = current->mm; int brightness; auo_win_info_t win_info_from_app; auo_color_key_info_t colkey_info; auo_color_val_info_t colval_info; bool panel_status; /* 0xFF00 ~ 0xFF7F : Control TCON 0xFF80 ~ 0xFF9F : Customer 0xFFA0 ~ 0xFFDF : Read info from TCON 0xFFE0 ~ 0xFFFF : Utility or test */ switch(cmd) { /* [MTR] */ case IOCTL_AUO_SENDCOMMAND: { sAUOCommand cmd; unsigned char buffer[2048]; unsigned char *user_buffer; unsigned long user_buflen, copysize, copysize16; unsigned short *ptr16; if (copy_from_user (&cmd, argp, sizeof(cmd))) return -EFAULT; /* Now execute the command */ Epaper_sendCommandStart(&cmd); //INFOL(INFO_VERBOSE, ("/* Seventh: Send data if needed */")); if (GET_COMMAND_HAVE_DATA(cmd.cmd) != 0) { //INFOL(INFO_VERBOSE, ("Yes, we have data to send!")); user_buflen = cmd.datalen; user_buffer = (unsigned char *)cmd.data; while (user_buflen != 0) { copysize = user_buflen; if (user_buflen > sizeof(buffer)) copysize = sizeof(buffer); if ( copy_from_user(buffer, user_buffer, copysize) ) return -EFAULT; copysize16 = (copysize + 1) / 2; //printk(KERN_ERR "cp16=%ld cp=%ld\n", copysize16, copysize); ptr16 = (unsigned short *) buffer; Epaper_sendData(buffer, copysize16); user_buflen -= copysize; user_buffer += copysize; } } Epaper_sendCommandEnd(&cmd); } break; /* [/MTR] */ //********************************************************************************* case AUOFB_IOCTL_TCON_GET_BUSY_STATUS: //busy pin panel_status = is_Epaper_Write_Ready_No_Wait(); if(copy_to_user((void *)arg, (const void *) &panel_status, sizeof(bool))) return -EFAULT; break; case AUOFB_IOCTL_SW_REFRESH: //DPRINTK("\nAUOFB full update!!!"); if ( 0 == LOCK_AUOFB_ENTRY() ) { w_partial_info.x = 0; w_partial_info.y = 0; w_partial_info.w = H_RESOLUTION; w_partial_info.h = V_RESOLUTION; w_partial_info.mode = 0; Epaper_Set_Partial_Update_Mode(w_partial_info.mode); if(!auofb_update_queue_is_full()) auofb_update_queue_put(w_partial_info); LOCK_AUOFB_EXIT(); } wake_update_display_thread(); break; case AUOFB_IOCTL_TCON_PARTIAL_UPDATE: DPRINTK("\nAUOFB partial update!!!"); if ( 0 == LOCK_AUOFB_ENTRY() ) { //if(is_Epaper_Write_Ready()) { if(copy_from_user(&w_partial_info, (_partial_update_info *) arg, sizeof(_partial_update_info))) return -EFAULT; DPRINTK("\nAUOFB partial update, (%d,%d,%d,%d,%d)!!!", w_partial_info.mode, w_partial_info.x, w_partial_info.y, w_partial_info.w, w_partial_info.h); if(auo_fb_is_update_region_legal() != 0) { LOCK_AUOFB_EXIT(); return -EFAULT; } if( (w_partial_info.w*w_partial_info.h) >= u32FullUpdateThreshold ) { w_partial_info.x = 0; w_partial_info.y = 0; w_partial_info.w = H_RESOLUTION; w_partial_info.h = V_RESOLUTION; } Epaper_Set_Partial_Update_Mode(w_partial_info.mode); if(!auofb_update_queue_is_full()) auofb_update_queue_put(w_partial_info); } LOCK_AUOFB_EXIT(); } wake_update_display_thread(); break; case AUOFB_IOCTL_TCON_SHUTDOWN: //shutdown TCON //AUO T-CON Standby Epaper_Enter_Standby_Mode(1); msleep(250); //AUO T-CON Sleep Epaper_Enter_Sleep_Mode(1); //Shutdown T-CON Power Epaper_Power(0); //Shutdown i80 of s3c EPaper_CloseLcdPort(); //msleep(1000); u32PowerState = EN_EPD_DEVICE_POWER_STATE_D3; break; case AUOFB_IOCTL_TCON_STANDBY: //TCON Standby if(u32PowerState == EN_EPD_DEVICE_POWER_STATE_D0) { Epaper_Enter_Standby_Mode(1); msleep(250); //TCON need at least 64ms to enter standby mode u32PowerState = EN_EPD_DEVICE_POWER_STATE_D1; } break; case AUOFB_IOCTL_TCON_WAKEUP: //TCON Wakeup (leave standby) if(u32PowerState == EN_EPD_DEVICE_POWER_STATE_D1) { Epaper_Enter_Standby_Mode(0); u32PowerState = EN_EPD_DEVICE_POWER_STATE_D0; } break; case AUOFB_IOCTL_TCON_SLEEP: //TCON Sleep if(u32PowerState == EN_EPD_DEVICE_POWER_STATE_D1) { Epaper_Enter_Sleep_Mode(1); u32PowerState = EN_EPD_DEVICE_POWER_STATE_D2; } break; case AUOFB_IOCTL_TCON_NO_SLEEP: //TCON no Sleep if(u32PowerState == EN_EPD_DEVICE_POWER_STATE_D2) { Epaper_Enter_Sleep_Mode(0); u32PowerState = EN_EPD_DEVICE_POWER_STATE_D1; } break; case AUOFB_IOCTL_TCON_REFRESH: //Display refresh if(is_Epaper_Write_Ready()) Epaper_Display_Refresh(); break; case AUOFB_IOCTL_SET_UPDATE_THRESHOLD: //Set u32FullUpdateThreshold if(copy_from_user(&u32FullUpdateThreshold, (unsigned long*) arg, sizeof(unsigned long))) return -EFAULT; break; case AUOFB_IOCTL_TCON_RESET: //TCON RESET command if(is_Epaper_Write_Ready()) Epaper_Reset(); else return -EFAULT; break; case AUOFB_IOCTL_TCON_INIT: break; case AUOFB_IOCTL_TCON_UPDATE_LUT: { unsigned char* lut_data = NULL; lut_data = __get_free_pages(GFP_KERNEL, get_order(AUO_LUT_LENGTH)); if(copy_from_user(lut_data, (unsigned char*) arg, AUO_LUT_LENGTH)) return -EFAULT; Epaper_Update_LUT((unsigned short*)lut_data,AUO_LUT_LENGTH/2 ); free_pages((unsigned long)lut_data, get_order(AUO_LUT_LENGTH)); break; } case AUOFB_IOCTL_TCON_POWER_STATE: { unsigned long UserPowerState = 0; if(copy_from_user(&UserPowerState, (unsigned long*) arg, sizeof(unsigned long))) return -EFAULT; switch(u32PowerState) { case EN_EPD_DEVICE_POWER_STATE_D0: switch(UserPowerState) { case EN_EPD_DEVICE_POWER_STATE_D0: //do nothing break; case EN_EPD_DEVICE_POWER_STATE_D1: Epaper_Enter_Standby_Mode(1); msleep(250); //TCON need at least 64ms to enter standby mode break; case EN_EPD_DEVICE_POWER_STATE_D2: //AUO T-CON Standby Epaper_Enter_Standby_Mode(1); msleep(250); //AUO T-CON Sleep Epaper_Enter_Sleep_Mode(1); break; case EN_EPD_DEVICE_POWER_STATE_D3: //AUO T-CON Standby Epaper_Enter_Standby_Mode(1); msleep(250); //AUO T-CON Sleep Epaper_Enter_Sleep_Mode(1); //Shutdown T-CON Power Epaper_Power(0); //Shutdown i80 of s3c EPaper_CloseLcdPort(); //msleep(1000); break; default: return -EFAULT; } break; case EN_EPD_DEVICE_POWER_STATE_D1: switch(UserPowerState) { case EN_EPD_DEVICE_POWER_STATE_D0: Epaper_Enter_Standby_Mode(0); break; case EN_EPD_DEVICE_POWER_STATE_D1: //do nothing break; case EN_EPD_DEVICE_POWER_STATE_D2: Epaper_Enter_Sleep_Mode(1); break; case EN_EPD_DEVICE_POWER_STATE_D3: Epaper_Enter_Sleep_Mode(1); //Shutdown T-CON Power Epaper_Power(0); //Shutdown i80 of s3c EPaper_CloseLcdPort(); //msleep(1000); break; default: return -EFAULT; } break; case EN_EPD_DEVICE_POWER_STATE_D2: switch(UserPowerState) { case EN_EPD_DEVICE_POWER_STATE_D0: Epaper_Enter_Sleep_Mode(0); Epaper_Enter_Standby_Mode(0); break; case EN_EPD_DEVICE_POWER_STATE_D1: Epaper_Enter_Sleep_Mode(0); break; case EN_EPD_DEVICE_POWER_STATE_D2: //do nothing break; case EN_EPD_DEVICE_POWER_STATE_D3: //Shutdown T-CON Power Epaper_Power(0); //Shutdown i80 of s3c EPaper_CloseLcdPort(); //msleep(1000); break; default: return -EFAULT; } break; case EN_EPD_DEVICE_POWER_STATE_D3: switch(UserPowerState) { case EN_EPD_DEVICE_POWER_STATE_D0: Epaper_SetLcdPort(); msleep(100); break; case EN_EPD_DEVICE_POWER_STATE_D1: //not allowed return -EFAULT; case EN_EPD_DEVICE_POWER_STATE_D2: //not allowed return -EFAULT; case EN_EPD_DEVICE_POWER_STATE_D3: //do nothing break; default: return -EFAULT; } break; default: return -EFAULT; } u32PowerState = UserPowerState; break; } //********************************************************************************* case AUOFB_IOCTL_TCON_GET_TEMPERATURE: //Get Tempterature if(is_Epaper_Write_Ready()) Epaper_Read_R_TEMP(&u16Temperature,&u16EPDType,&u16PanelType,&u16LUTVersion); if(copy_to_user((void *)arg, (const void *) &u16Temperature, sizeof(unsigned short))) return -EFAULT; break; case AUOFB_IOCTL_TCON_GET_EPD_TYPE: //Get EPD type if(is_Epaper_Write_Ready()) Epaper_Read_R_TEMP(&u16Temperature,&u16EPDType,&u16PanelType,&u16LUTVersion); if(copy_to_user((void *)arg, (const void *) &u16EPDType, sizeof(unsigned short))) return -EFAULT; break; case AUOFB_IOCTL_TCON_GET_PANEL_TYPE: //Get Panel type if(is_Epaper_Write_Ready()) Epaper_Read_R_TEMP(&u16Temperature,&u16EPDType,&u16PanelType,&u16LUTVersion); if(copy_to_user((void *)arg, (const void *) &u16PanelType, sizeof(unsigned short))) return -EFAULT; break; case AUOFB_IOCTL_TCON_GET_LUT_INFO: //Get LUT version if(is_Epaper_Write_Ready()) Epaper_Read_R_TEMP(&u16Temperature,&u16EPDType,&u16PanelType,&u16LUTVersion); if(copy_to_user((void *)arg, (const void *) &u16LUTVersion, sizeof(unsigned short))) return -EFAULT; break; //********************************************************************************* case AUOFB_IOCTL_SHOW_PROGRESS_BAR: { int percent = 0; if(copy_from_user(&percent, (int *) arg, sizeof(int))) return -EFAULT; Epaper_Show_Progress(percent); break; } case AUOFB_IOCTL_CLEAN_EPD: { Epaper_Clean_Panel(); break; } default: return -EINVAL; } return 0; } /* ------------------------------------------------------------------------- */ /* * Frame buffer operations */ static struct fb_ops auofb_ops = { .owner = THIS_MODULE, .fb_check_var = auofb_check_var, .fb_set_par = auofb_set_par, .fb_blank = auofb_blank, .fb_pan_display = auofb_pan_display, .fb_setcolreg = auofb_setcolreg, .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, //.fb_cursor = soft_cursor, .fb_ioctl = auo_fb_ioctl, .fb_mmap = auo_fb_mmap, }; /* ------------------------------------------------------------------------- */ struct fb_monspecs monspecs __initdata = { .hfmin = 30000, .hfmax = 70000, .vfmin = 50, .vfmax = 65, }; struct page *vmalloc_2_page(void *addr) { unsigned long lpage; pgd_t *pgd; pmd_t *pmd; pte_t *pte; struct page *page; lpage = (unsigned long)(addr); spin_lock(&init_mm.page_table_lock); pgd = pgd_offset(&init_mm, lpage); pmd = pmd_offset(pgd, lpage); pte = pte_offset_map(pmd, lpage); page = pte_page(*pte); spin_unlock(&init_mm.page_table_lock); return page; //return vmalloc_to_page(addr); } int init_page_array(void) { int i; numpages = (videomemorysize >> PAGE_SHIFT) + 1; videopages = kmalloc(numpages * sizeof(struct page *), GFP_KERNEL); if (videopages == NULL) { return 1; } for (i = 0; (i << PAGE_SHIFT) < videomemorysize; i++) { videopages[i] = vmalloc_2_page(pu8Framebuffer + (i << PAGE_SHIFT)); } return 0; } int clear_page_array(void) { if (videopages != NULL) { kfree(videopages); } return 0; } void auo_fb_init_fbinfo(struct auo_fb_info *finfo, char *drv_name, int index) { int i = 0; //Epaper is open at boot code /*Epaper_SetLcdPort(); Epaper_Init(AUO_EPAPER_PHYSICAL_H_RESOLUTION, AUO_EPAPER_PHYSICAL_V_RESOLUTION, 0, 0, 0, 0, 0, 0);*/ #ifdef EPD_HW_ROTATE Epaper_Init(AUO_EPAPER_PHYSICAL_H_RESOLUTION, AUO_EPAPER_PHYSICAL_V_RESOLUTION, 90, 0, 0, 0, 0, 0); #endif strcpy(finfo->fb.fix.id, drv_name); finfo->win_id = index; finfo->fb.fix.type = FB_TYPE_PACKED_PIXELS; finfo->fb.fix.type_aux = 0; finfo->fb.fix.xpanstep = 0; finfo->fb.fix.ypanstep = 0; finfo->fb.fix.ywrapstep = 0; finfo->fb.fix.accel = FB_ACCEL_NONE; finfo->fb.fbops = &auofb_ops; finfo->fb.flags = FBINFO_FLAG_DEFAULT; finfo->fb.monspecs = monspecs; finfo->fb.pseudo_palette = &finfo->pseudo_pal; finfo->fb.var.nonstd = 0; finfo->fb.var.activate = FB_ACTIVATE_NOW; finfo->fb.var.accel_flags = 0; finfo->fb.var.vmode = FB_VMODE_NONINTERLACED; finfo->fb.var.xoffset = auo_mach_info.xoffset; finfo->fb.var.yoffset = auo_mach_info.yoffset; if(index==0){ finfo->fb.var.height = auo_mach_info.height; finfo->fb.var.width = auo_mach_info.width; finfo->fb.var.xres = auo_mach_info.xres; finfo->fb.var.xres_virtual = auo_mach_info.xres_virtual; finfo->fb.var.yres = auo_mach_info.yres; finfo->fb.var.yres_virtual = auo_mach_info.yres_virtual; } else{ finfo->fb.var.height = auo_mach_info.osd_height; finfo->fb.var.width = auo_mach_info.osd_width; finfo->fb.var.xres = auo_mach_info.osd_xres; finfo->fb.var.xres_virtual = auo_mach_info.osd_xres_virtual; finfo->fb.var.yres = auo_mach_info.osd_yres; finfo->fb.var.yres_virtual = auo_mach_info.osd_yres_virtual; } finfo->fb.var.bits_per_pixel = auo_mach_info.bpp; finfo->fb.var.pixclock = auo_mach_info.pixclock; finfo->fb.var.hsync_len = auo_mach_info.hsync_len; finfo->fb.var.left_margin = auo_mach_info.left_margin; finfo->fb.var.right_margin = auo_mach_info.right_margin; finfo->fb.var.vsync_len = auo_mach_info.vsync_len; finfo->fb.var.upper_margin = auo_mach_info.upper_margin; finfo->fb.var.lower_margin = auo_mach_info.lower_margin; finfo->fb.var.sync = auo_mach_info.sync; finfo->fb.var.grayscale = auo_mach_info.cmap_grayscale; videomemorysize = finfo->fb.fix.smem_len = finfo->fb.var.xres_virtual * finfo->fb.var.yres_virtual * auo_mach_info.bytes_per_pixel; //DPRINTK("\nsmem_len=%d * %d * %d", finfo->fb.var.xres_virtual, finfo->fb.var.yres_virtual, auo_mach_info.bytes_per_pixel); finfo->fb.fix.line_length = finfo->fb.var.width * auo_mach_info.bytes_per_pixel; for (i = 0; i < 256; i++) finfo->palette_buffer[i] = PALETTE_BUFF_CLEAR; } /* static int __init xxfb_probe (struct device *device) -- for platform devs */ int __init auo_fb_probe(struct platform_device *pdev) { char driver_name[]="s3c_fb"; int ret,i; int index=0; DPRINTK("\n!!!!!!!!!!!init AUO EINK"); auo_fb_init_fbinfo(&info, driver_name, 0); /* if (!request_mem_region((unsigned long)S3C24XX_VA_LCD, SZ_1M, "s3c-lcd")) { ret = -EBUSY; return ret; } */ /* * Dynamically allocate info and par */ //pu8Framebuffer = vmalloc(800*600*3); ///pu8Framebuffer = vmalloc(info.fb.fix.smem_len); pu8Framebuffer = vmalloc(V_RESOLUTION*H_RESOLUTION*2); pu16Translatebuffer = vmalloc(V_RESOLUTION*H_RESOLUTION/2); pu8RotateBuffer = vmalloc(V_RESOLUTION*H_RESOLUTION*2); /* * Here we set the screen_base to the virtual memory address * for the framebuffer. Usually we obtain the resource address * from the bus layer and then translate it to virtual memory * space via ioremap. Consult ioport.h. */ info.fb.screen_base = pu8Framebuffer; //pu8Framebuffer = info.fb.screen_base = ioremap_nocache(S3C24XX_PA_LCD, SZ_1M); info.fb.fbops = &auofb_ops; info.fb.fix.smem_start = (unsigned long)pu8Framebuffer; ///info.fb.fix.smem_start =S3C24XX_PA_LCD; /* * Set up flags to indicate what sort of acceleration your * driver can provide (pan/wrap/copyarea/etc.) and whether it * is a module -- see FBINFO_* in include/linux/fb.h * * If your hardware can support any of the hardware accelerated functions * fbcon performance will improve if info->flags is set properly. * * FBINFO_HWACCEL_COPYAREA - hardware moves * FBINFO_HWACCEL_FILLRECT - hardware fills * FBINFO_HWACCEL_IMAGEBLIT - hardware mono->color expansion * FBINFO_HWACCEL_YPAN - hardware can pan display in y-axis * FBINFO_HWACCEL_YWRAP - hardware can wrap display in y-axis * FBINFO_HWACCEL_DISABLED - supports hardware accels, but disabled * FBINFO_READS_FAST - if set, prefer moves over mono->color expansion * FBINFO_MISC_TILEBLITTING - hardware can do tile blits * * NOTE: These are for fbcon use only. */ init_page_array(); /* This has to been done !!! */ fb_alloc_cmap(&info.fb.cmap, 256, 0); //Ivan test sema_init(&vma_list_semaphore, 1); /* * For drivers that can... */ auofb_check_var(&info.fb.var, &info.fb); /* * Does a call to fb_set_par() before register_framebuffer needed? This * will depend on you and the hardware. If you are sure that your driver * is the only device in the system, a call to fb_set_par() is safe. * * Hardware in x86 systems has a VGA core. Calling set_par() at thisEpaper_Enter_Sleep_Mode(1); * point will corrupt the VGA console, so it might be safer to skip a * call to set_par here and just allow fbcon to do it for you. */ /* auofb_set_par(info); */ if (register_framebuffer(&info.fb) < 0) return -EINVAL; start_update_display_thread(); //timer /* init_timer(&panel_timer_qisda); panel_timer_qisda.function =panel_timer_handler_qisda; INIT_WORK(&workq_panel_update,panel_update_workqueue); panel_timer_qisda.expires = jiffies + (2*HZ); add_timer(&panel_timer_qisda); */ u32PowerState = EN_EPD_DEVICE_POWER_STATE_D0; memset((unsigned char*)partial_info_queue, 0x0, sizeof(_partial_update_info)*PARTIAL_INFO_QUEUE_SIZE); //refresh logo if ( 0 == LOCK_AUOFB_ENTRY() ) { //if(is_Epaper_Write_Ready()) { w_partial_info.x = 0; w_partial_info.y = 0; w_partial_info.w = H_RESOLUTION; w_partial_info.h = V_RESOLUTION; w_partial_info.mode = 0; //test DPRINTK("\nAUOFB partial init, (%d,%d,%d,%d,%d)!!!", w_partial_info.mode, w_partial_info.x, w_partial_info.y, w_partial_info.w, w_partial_info.h); Epaper_Set_Partial_Update_Mode(w_partial_info.mode); } LOCK_AUOFB_EXIT(); } auofb_update_queue_put(w_partial_info); wake_update_display_thread(); start_boot_progress_bar_thread(); if(is_Epaper_Write_Ready()) Epaper_Read_R_TEMP(&u16Temperature,&u16EPDType,&u16PanelType,&u16LUTVersion); printk("\nTCON Temperature=%d\nEPD Type=0x%x\nPanel Type=0x%x\nLUT=0x%x\n", u16Temperature/2,u16EPDType, u16PanelType, u16LUTVersion); return 0; } /* ----------------------------------------- * s3c_fb_stop_lcd & s3c_fb_start_lcd * * shutdown/ start the lcd controller */ static void s3c_fb_stop_lcd(void) { unsigned long flags; unsigned long tmp; local_irq_save(flags); tmp = __raw_readl(S3C_VIDCON0); __raw_writel(tmp & ~(S3C_VIDCON0_ENVID_ENABLE | S3C_VIDCON0_ENVID_F_ENABLE), S3C_VIDCON0); local_irq_restore(flags); } void s3c_fb_start_lcd(void) { unsigned long flags; unsigned long tmp; local_irq_save(flags); tmp = __raw_readl(S3C_VIDCON0); __raw_writel(tmp | S3C_VIDCON0_ENVID_ENABLE | S3C_VIDCON0_ENVID_F_ENABLE, S3C_VIDCON0); local_irq_restore(flags); } /* * Cleanup */ static int auofb_remove(struct platform_device *pdev) { struct fb_info *fbinfo = platform_get_drvdata(pdev); struct auo_fb_info *info = fbinfo->par; int irq; int index=0; vfree(pu8Framebuffer); vfree(pu16Translatebuffer); vfree(pu8RotateBuffer); unregister_framebuffer(&(info[index].fb)); return 0; } #ifdef CONFIG_PM static struct sleep_save lcd_save[] = { SAVE_ITEM(S3C_VIDCON0),SAVE_ITEM(S3C_VIDCON1), SAVE_ITEM(S3C_VIDTCON0),SAVE_ITEM(S3C_VIDTCON1), SAVE_ITEM(S3C_VIDTCON2),SAVE_ITEM(S3C_WINCON0), SAVE_ITEM(S3C_WINCON1), SAVE_ITEM(S3C_VIDINTCON),SAVE_ITEM(S3C_SYSIFCON0), SAVE_ITEM(S3C_SIFCCON0), SAVE_ITEM(S3C_CPUTRIGCON2),SAVE_ITEM(S3C_VIDOSD0A), SAVE_ITEM(S3C_VIDOSD0B),SAVE_ITEM(S3C_VIDOSD0C), SAVE_ITEM(S3C_VIDOSD1A),SAVE_ITEM(S3C_VIDOSD1B), SAVE_ITEM(S3C_VIDOSD1C),SAVE_ITEM(S3C_VIDW00ADD0B0), SAVE_ITEM(S3C_VIDW00ADD0B1),SAVE_ITEM(S3C_VIDW01ADD0), SAVE_ITEM(S3C_VIDW00ADD1B0),SAVE_ITEM(S3C_VIDW00ADD1B1), SAVE_ITEM(S3C_VIDW01ADD1),SAVE_ITEM(S3C_VIDW00ADD2B0), SAVE_ITEM(S3C_VIDW00ADD2B1),SAVE_ITEM(S3C_VIDW01ADD2), }; /* suspend and resume support for the AUO T-CON */ static int auofb_suspend(struct platform_device *dev, pm_message_t state) { if(is_Epaper_Write_Ready()) { //Suspend LCD controller //s3c_fb_stop_lcd(); //s3c2410_pm_do_save(lcd_save, ARRAY_SIZE(lcd_save)); //AUO T-CON Standby Epaper_Enter_Standby_Mode(1); msleep(250); //AUO T-CON Sleep Epaper_Enter_Sleep_Mode(1); //Shutdown T-CON Power Epaper_Power(0); //Shutdown i80 of s3c EPaper_CloseLcdPort(); //msleep(1000); DPRINTK("\nAUOFB Suspend"); u32PowerState = EN_EPD_DEVICE_POWER_STATE_D3; return 0; } return -EINVAL; } static int auofb_resume(struct platform_device *dev) { //s3c2410_pm_do_restore(lcd_save, ARRAY_SIZE(lcd_save)); //s3c_fb_start_lcd(); //Epaper_Power(1); //msleep(1000); DPRINTK("\nAUOFB Resume"); //Ivan : Reset again? Epaper_SetLcdPort(); //AUO T-CON leave standby (If shutdown power of TCON, then do not need to leave standby mode) //Epaper_Enter_Standby_Mode(0); //AUO T-CON leave sleep //Epaper_Enter_Sleep_Mode(0); msleep(100); //sleep for RST_N pull high u32PowerState = EN_EPD_DEVICE_POWER_STATE_D0; #ifdef EPD_HW_ROTATE Epaper_Init(AUO_EPAPER_PHYSICAL_H_RESOLUTION, AUO_EPAPER_PHYSICAL_V_RESOLUTION, 90, 0, 0, 0, 0, 0); #endif return 0; } #define auofb_shutdown NULL #else //no CONFIG_PM #define auofb_shutdown NULL #define auofb_suspend NULL #define auofb_resume NULL #endif //CONFIG_PM /* for platform devices */ static struct platform_driver auo_fb_driver = { .probe = auo_fb_probe, .remove = auofb_remove, .shutdown = auofb_shutdown, .suspend = auofb_suspend, .resume = auofb_resume, .driver = { .name = "s3c-lcd", .owner = THIS_MODULE, }, }; int __devinit auofb_init(void) { int ret = 0; return platform_driver_register(&auo_fb_driver); } static void __exit auofb_cleanup(void) { platform_driver_unregister(&auo_fb_driver); } /* * Setup */ /* * Modularization */ module_init(auofb_init); module_exit(auofb_cleanup); MODULE_AUTHOR(""); MODULE_DESCRIPTION("Framebuffer driver for the AUO-EINK"); MODULE_LICENSE("GPL");