2021-11-21 00:20:20 +00:00

3778 lines
100 KiB
C
Raw Permalink Blame History

/*
* linux/drivers/video/auofb.c -- for AUO epaper frame buffer device
*
* Modified by Ivan.Ruan
*
* Created 2009/04/01 by Ivan.Ruan
*
*
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/dma-mapping.h>
#include <linux/string.h>
#include <linux/ioctl.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/freezer.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/div64.h>
#include <linux/auofb_ioctl.h>
//#include <asm/mach/map.h>
#include <asm/arch/regs-lcd.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-timer.h>
#include <asm/arch/regs-watchdog.h>
#include <asm/arch/idle.h>
#include <asm/arch/regs-s3c2450-clock.h>
#include "epaper.h"
#include "auofb.h"
#ifdef CONFIG_PM
#include <linux/pm.h>
#include <asm/plat-s3c24xx/pm.h>
#endif
#include <asm/io.h>
#include <linux/platform_device.h>
//#define FRAMEBUFFER_DMA
#define EPD_HW_ROTATE
//#define EPD_HW_ROTATE_NO_MODE4
//#define AUOFB_ROTATE
#if defined(CONFIG_QISDA_QD060B00) || defined(CONFIG_QISDA_QD060N00_DVT1_1) || defined(CONFIG_QISDA_QD090B00) || defined(CONFIG_QISDA_QD090B00_EVT1)||defined(CONFIG_QISDA_SH060B00)
#define EPD_ENABLE_PRE_DISPLAY
#endif
#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 FRAMEBUFFER_DMA
#define UPDATE_WIDTH_MIN 12
#define UPDATE_WIDTH_MULTIPLES 4
#define UPDATE_HEIGHT_MIN 8
#define UPDATE_HEIGHT_MULTIPLES 4
#else
#define UPDATE_WIDTH_MIN 12
#define UPDATE_WIDTH_MULTIPLES 4
#define UPDATE_HEIGHT_MIN 8
#define UPDATE_HEIGHT_MULTIPLES 4
#endif
#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 */
#define WINCONx_BIT_SWAP_ON (1<<2) //shift on basis of half-word swap
#define WINCONx_BYTE_SWAP_ON (1<<1) //shift on basis of half-word swap
#define WINCONx_HALFW_SWAP_ON (1<<0) //shift on basis of half-word swap
#define WINCONx_4WORD_BURST (2)
#define WINCONx_8WORD_BURST (1)
#define WINCONx_16WORD_BURST (0)
#define WINCONx_PLANE_BLENDING (0)
#define WINCONx_PIXEL_BLENDING (1)
#define WINCONx_1BPP_PALLET (0)
#define WINCONx_2BPP_PALLET (1)
#define WINCONx_4BPP_PALLET (2)
#define WINCONx_8BPP_PALLET (3)
#define WINCONx_8BPP_NO_PALLET (4)
#define WINCONx_16BPP_565 (5)
#define WINCONx_16BPP_A555 (6)
#define WINCONx_16BPP_1555 (7)
#define WINCONx_18BPP_666 (8)
#define WINCONx_18BPP_A665 (9)
#define WINCONx_19BPP_A666 (10)
#define WINCONx_24BPP_888 (11)
#define WINCONx_24BPP_A887 (12)
#define WINCONx_25BPP_A888 (13)
#define WINCONx_ALPHA_MODE_0 (0)
#define WINCONx_ALPHA_MODE_1 (1)
//bit shift
#define WINCON_BUFSEL (23)
#define WINCON_BUFAUTOEN (22)
#define WINCON_BIT_SWAP_S (18)
#define WINCON_BYTE_SWAP_S (17)
#define WINCON_SWAP_S (16)
#define WINCON_BURSTLEN_S (9)
#define WINCON_BLENDING_S (6)
#define WINCON_BPP_S (2)
#define WINCON_ALPHA_S (1)
//* VIDWxADD2
//bit shift
#define VIDWxADD2_OFFSET_SIZE_S (13)
#define VIDWxADD2_PAGE_WIDTH_S (0)
//* VIDOSDxA,B,C
//bit shift
#define VIDOSDxAB_HORIZON_X_S (11)
#define VIDOSDxAB_VERTICAL_Y_S (0)
#define VIDOSDxC_ALPHA0_S (12)
#define LCD_OFF 0
#define LCD_ON 1
#define LCD_WIN_0 0
#define LCD_WIN_1 1
#define LCD_WIN_ALL 2
#define LCD_BUF_0 0
#define LCD_BUF_1 1
#if defined(AUO_EPAPER_6_INCH)
#if defined(EPD_HW_ROTATE)
#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)
#else
#define BOOT_PROGRESS_BAR_X 203
#define BOOT_PROGRESS_BAR_Y 95
#define BOOT_PROGRESS_BAR_W 8
#define BOOT_PROGRESS_BAR_H 413
#endif
#ifdef CONFIG_RESCUEOS_BUILD
#define BOOT_PROGRESS_BAR_DELAY_TIME 100 //2 sec = 420
#else
#define BOOT_PROGRESS_BAR_DELAY_TIME 250 //2 sec = 420
#endif
#else
#if defined(EPD_HW_ROTATE)
#define BOOT_PROGRESS_BAR_X 121
#define BOOT_PROGRESS_BAR_Y 259
#define BOOT_PROGRESS_BAR_W 528
#define BOOT_PROGRESS_BAR_H 8
#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
#endif
#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;
u_char * cpu_VideoPhysicalTemp_f1;
dma_addr_t map_VideoPhysicalTemp_f1;
typedef struct partial_update_info
{
int mode;
int x;
int y;
int w;
int h;
unsigned short u16EpaperCommand;
}_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;
#if defined(EPD_ENABLE_PRE_DISPLAY)
atomic_t gPowerOnFirstDisplay = ATOMIC_INIT(0); // to identify if a screen update is the first update after power on
#endif
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<><31>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;
T_DISPLAY_FRAME gStDisFrame;
//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)
{
#if defined(EPD_ENABLE_PRE_DISPLAY)
// { workaround for MMI first update not using mode 0 after T-Con power on + pre display cmd
if ((atomic_read(&gPowerOnFirstDisplay ) == 1))
{
if(put_region.mode == 0)
{
put_region.mode = 1;
}
atomic_set(&gPowerOnFirstDisplay, 0);
}
// } workaround for MMI first update not using mode 0 after T-Con power on + pre display cmd
#endif
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)];
}
}
}
#if defined(EPD_ENABLE_PRE_DISPLAY)
/* RGB table for RGB 565 */
unsigned short u16TableR[] =
{
0,
77,
154,
231,
308,
385,
462,
539,
616,
693,
770,
847,
924,
1001,
1078,
1155,
1232,
1309,
1386,
1463,
1540,
1617,
1694,
1771,
1848,
1925,
2002,
2079,
2156,
2233,
2310,
2387
};
unsigned short u16TableG[] =
{
0,
151,
302,
453,
604,
755,
906,
1057,
1208,
1359,
1510,
1661,
1812,
1963,
2114,
2265,
2416,
2567,
2718,
2869,
3020,
3171,
3322,
3473,
3624,
3775,
3926,
4077,
4228,
4379,
4530,
4681,
4832,
4983,
5134,
5285,
5436,
5587,
5738,
5889,
6040,
6191,
6342,
6493,
6644,
6795,
6946,
7097,
7248,
7399,
7550,
7701,
7852,
8003,
8154,
8305,
8456,
8607,
8758,
8909,
9060,
9211,
9362,
9513
};
unsigned short u16TableB[] =
{
0,
28,
56,
84,
112,
140,
168,
196,
224,
252,
280,
308,
336,
364,
392,
420,
448,
476,
504,
532,
560,
588,
616,
644,
672,
700,
728,
756,
784,
812,
840,
868
};
static void auofb_convert_RGB565(unsigned short w, unsigned short h, unsigned short* src_data, unsigned short* dst_data)
{
int i;
int length = w*h*auo_mach_info.bytes_per_pixel/8;
unsigned short u16val1, u16val2, u16val3, u16val4;
unsigned short u8R, u8G, u8B;
unsigned short* pu16TranslatePtr = dst_data;
unsigned short* pu16ProcessPtr = src_data;
unsigned short u16Pixel;
// printk("*** +%s\n", __func__);
for(i=0;i<length;i++)
{
// 1st pixel
u16Pixel = *(pu16ProcessPtr + 0);
u8R = ((u16Pixel & 0xF800) >> auo_fb_rgb_16.red.offset);
u8G = ((u16Pixel & 0x07E0) >> (auo_fb_rgb_16.green.offset+1));
u8B = ((u16Pixel & 0x001F) >> auo_fb_rgb_16.blue.offset);
u16val1 = (u16TableR[u8R] + u16TableG[u8G] + u16TableB[u8B]) >> 9;
// 2nd pixel
u16Pixel = *(pu16ProcessPtr + 1);
u8R = ((u16Pixel & 0xF800) >> auo_fb_rgb_16.red.offset);
u8G = ((u16Pixel & 0x07E0) >> (auo_fb_rgb_16.green.offset+1));
u8B = ((u16Pixel & 0x001F) >> auo_fb_rgb_16.blue.offset);
u16val2 = (u16TableR[u8R] + u16TableG[u8G] + u16TableB[u8B]) >> 5;
// 3rd pixel
u16Pixel = *(pu16ProcessPtr + 2);
u8R = ((u16Pixel & 0xF800) >> auo_fb_rgb_16.red.offset);
u8G = ((u16Pixel & 0x07E0) >> (auo_fb_rgb_16.green.offset+1));
u8B = ((u16Pixel & 0x001F) >> auo_fb_rgb_16.blue.offset);
u16val3 = (u16TableR[u8R] + u16TableG[u8G] + u16TableB[u8B]) >> 1;
// 4th pixel
u16Pixel = *(pu16ProcessPtr + 3);
u8R = ((u16Pixel & 0xF800) >> auo_fb_rgb_16.red.offset);
u8G = ((u16Pixel & 0x07E0) >> (auo_fb_rgb_16.green.offset+1));
u8B = ((u16Pixel & 0x001F) >> auo_fb_rgb_16.blue.offset);
u16val4 = (u16TableR[u8R] + u16TableG[u8G] + u16TableB[u8B]) << 3;
*pu16TranslatePtr = ( ( (u16val4) & 0xF000)
| ( (u16val3) & 0x0F00)
| ( (u16val2) & 0x00F0)
| ( (u16val1) & 0x000F) );
pu16TranslatePtr++;
pu16ProcessPtr = pu16ProcessPtr + 4;
}
// printk("*** -%s\n", __func__);
}
#else
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;
}
}
#endif
static void auofb_basic_display_setting( unsigned long win_num,unsigned long buf_num)
{
unsigned long screenwidth_in_byte=0,offsize_in_byte=0;
unsigned long offsize;
unsigned long tmp=0;
screenwidth_in_byte = H_RESOLUTION*4/8;
if((screenwidth_in_byte%64)!=0) //64 is depanded on WINCONx_16WORD_BURST
{
screenwidth_in_byte += 64 - (screenwidth_in_byte%64);
}
offsize =0;
offsize_in_byte = offsize*8/8;
// WINCON0/1
tmp = (0<<WINCON_BUFSEL)|(0<<WINCON_BUFAUTOEN)|(1<<WINCON_SWAP_S)|(0<<WINCON_BURSTLEN_S)|(5<<WINCON_BPP_S);
__raw_writel(tmp, S3C_WINCON0);
// WIN0/1 OSD(top)
tmp = (0<<VIDOSDxAB_HORIZON_X_S)|(0);
__raw_writel(tmp, S3C_VIDOSD0A);
// WIN0/1 OSD(bottom)
tmp = (((H_RESOLUTION)-1)<<VIDOSDxAB_HORIZON_X_S)|((V_RESOLUTION/4)-1);
__raw_writel(tmp, S3C_VIDOSD0B);
//=================
cpu_VideoPhysicalTemp_f1 = dma_alloc_writecombine(info.dev, H_RESOLUTION*V_RESOLUTION/2,
&map_VideoPhysicalTemp_f1, GFP_KERNEL);
memset(cpu_VideoPhysicalTemp_f1, 0xFF, H_RESOLUTION*V_RESOLUTION/2);
//=================
// WIN0/1 buffer start address
__raw_writel((unsigned long)map_VideoPhysicalTemp_f1, S3C_VIDW00ADD0B0);
// WIN0/1 buffer end address
__raw_writel((unsigned long)map_VideoPhysicalTemp_f1 + (screenwidth_in_byte+offsize_in_byte)*(V_RESOLUTION), S3C_VIDW00ADD1B0);
// WIN0/1 buffer size
__raw_writel((offsize_in_byte<<VIDWxADD2_OFFSET_SIZE_S)|screenwidth_in_byte, S3C_VIDW00ADD2B0);
__raw_writel(0, S3C_WIN0MAP);
//if (win_num>0)
{
__raw_writel(0, S3C_VIDOSD1C);
__raw_writel(0, S3C_W1KEYCON0);
__raw_writel(0, S3C_W1KEYCON1);
}
}
static void auofb_display_setting( unsigned long win_num,unsigned long buf_num, unsigned short x, unsigned short y, unsigned short w, unsigned short h)
{
unsigned long screenwidth_in_byte=0,offsize_in_byte=0;
unsigned long offsize;
unsigned long tmp=0;
printk("\n(%d, %d, %d, %d)\n", x,y,w,h);
screenwidth_in_byte = w*4/8;
if((screenwidth_in_byte%16)!=0) //16 is depanded on WINCONx_16WORD_BURST
{
screenwidth_in_byte += 16 - (screenwidth_in_byte%16);
}
offsize =0;
offsize_in_byte = offsize*8/8;
// WINCON0/1
tmp = (0<<WINCON_BUFSEL)|(0<<WINCON_BUFAUTOEN)|(0<<WINCON_BIT_SWAP_S)|(0<<WINCON_BYTE_SWAP_S)|(1<<WINCON_SWAP_S)|(WINCONx_4WORD_BURST<<WINCON_BURSTLEN_S)|(5<<WINCON_BPP_S);
__raw_writel(tmp, S3C_WINCON0);
// WIN0/1 OSD(top)
tmp = ((0)<<VIDOSDxAB_HORIZON_X_S)|(0);
__raw_writel(tmp, S3C_VIDOSD0A);
// WIN0/1 OSD(bottom)
tmp = (((w-1))<<VIDOSDxAB_HORIZON_X_S)|((h-1));
__raw_writel(tmp, S3C_VIDOSD0B);
// WIN0/1 buffer start address
__raw_writel((unsigned long)map_VideoPhysicalTemp_f1, S3C_VIDW00ADD0B0);
// WIN0/1 buffer end address
__raw_writel((unsigned long)map_VideoPhysicalTemp_f1 + (screenwidth_in_byte+offsize_in_byte)*(h), S3C_VIDW00ADD1B0);
// WIN0/1 buffer size
__raw_writel((offsize_in_byte<<VIDWxADD2_OFFSET_SIZE_S)|screenwidth_in_byte, S3C_VIDW00ADD2B0);
}
static void auofb_LcdEnvidOnOff(unsigned char onoff)
{
unsigned long tmp = 0;
if(onoff==LCD_ON)
{
tmp = __raw_readl(S3C_VIDCON0);
tmp |= (3);
__raw_writel(tmp, S3C_VIDCON0);
}
else
{
tmp = __raw_readl(S3C_VIDCON0);
tmp &= (~1);
__raw_writel(tmp, S3C_VIDCON0);
__raw_writel((1<<0), S3C_CPUTRIGCON2);
while( 1) // Check end of frame
{
tmp = __raw_readl(S3C_VIDCON0);
if(!(tmp&1))
break;
msleep(20);
}
}
}
static void auofb_LcdWindowOnOff(unsigned char num, unsigned char onoff)
{
unsigned long tmp = 0;
switch(num)
{
case LCD_WIN_0:
if(onoff==LCD_ON)
{
tmp = __raw_readl(S3C_WINCON0);
tmp |= 0x01;
__raw_writel(tmp, S3C_WINCON0);
}
else
{
tmp = __raw_readl(S3C_WINCON0);
tmp &= ~0x01;
__raw_writel(tmp, S3C_WINCON0);
}
break;
case LCD_WIN_1:
if(onoff==LCD_ON)
{
tmp = __raw_readl(S3C_WINCON1);
tmp |= 0x01;
__raw_writel(tmp, S3C_WINCON1);
}
else
{
tmp = __raw_readl(S3C_WINCON1);
tmp &= ~0x01;
__raw_writel(tmp, S3C_WINCON1);
}
break;
case LCD_WIN_ALL:
if(onoff==LCD_ON)
{
tmp = __raw_readl(S3C_WINCON0);
tmp |= 0x01;
__raw_writel(tmp, S3C_WINCON0);
tmp = __raw_readl(S3C_WINCON1);
tmp |= 0x01;
__raw_writel(tmp, S3C_WINCON1);
}
else
{
tmp = __raw_readl(S3C_WINCON0);
tmp &= ~0x01;
__raw_writel(tmp, S3C_WINCON0);
tmp = __raw_readl(S3C_WINCON1);
tmp &= ~0x01;
__raw_writel(tmp, S3C_WINCON1);
}
default:
break;
}
return;
}
static void auofb_Display_Start(char win_num) // 0: LCD_WIN_0, 1: LCD_WIN_1, 2: LCD_WIN_ALL
{
auofb_LcdWindowOnOff(win_num,LCD_ON);
auofb_LcdEnvidOnOff(LCD_ON);
#if defined(EPD_ENABLE_PRE_DISPLAY)
mdelay(1);
#else
msleep(1);
#endif
__raw_writel((1<<0), S3C_CPUTRIGCON2);
return;
}
static void auofb_Display_End(unsigned char win_num)
{
auofb_LcdWindowOnOff(win_num,LCD_OFF);
auofb_LcdEnvidOnOff(LCD_OFF);
return;
}
static void auofb_Disp(T_DISPLAY_FRAME tmpDispFrame)
{
#ifdef FRAMEBUFFER_DMA
int get_mode = Epaper_Get_Partial_Update_Mode();
if((get_mode == PARTIAL_DSP_MODE_4) || (get_mode == PARTIAL_DSP_MODE_4_W))
{
Epaper_Disp(tmpDispFrame);
}
else
{
printk("\nDMA out, (x,y,w,h)=(%d,%d,%d,%d)\n",tmpDispFrame.tFrameRange.X, tmpDispFrame.tFrameRange.Y, tmpDispFrame.tFrameRange.W, tmpDispFrame.tFrameRange.H);
auofb_display_setting(0,0, tmpDispFrame.tFrameRange.X, tmpDispFrame.tFrameRange.Y, tmpDispFrame.tFrameRange.W, tmpDispFrame.tFrameRange.H);
Epaper_Pre_DMA_Disp_Start(tmpDispFrame);
if(is_Epaper_Write_Ready())
{
auofb_Display_Start(0);
auofb_Display_End(0);
}
Epaper_Pre_DMA_Disp_Stop(tmpDispFrame);
}
#else
Epaper_Disp(tmpDispFrame);
#endif
}
/*
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;
int draw_len = 0;
if(percent == 0)
return;
memset((unsigned char*)pu16Translatebuffer, 0xff, BOOT_PROGRESS_BAR_W*BOOT_PROGRESS_BAR_H/4*2);
#if defined(EPD_HW_ROTATE)
if((BOOT_PROGRESS_BAR_W*percent/100)%4 != 0)
{
draw_len = (BOOT_PROGRESS_BAR_W*percent/100) + (4)-((BOOT_PROGRESS_BAR_W*percent/100)%4);
}
else
draw_len = (BOOT_PROGRESS_BAR_W*percent/100);
for(i=0; i< BOOT_PROGRESS_BAR_H; i++)
{
memset((unsigned char*)pu16Translatebuffer + (BOOT_PROGRESS_BAR_W/2)*i, 0x0, (draw_len/2));
}
#else
memset((unsigned char*)pu16Translatebuffer+(BOOT_PROGRESS_BAR_H-(BOOT_PROGRESS_BAR_H*percent/100))*line_bytes, 0x0, (BOOT_PROGRESS_BAR_H*percent/100)*line_bytes);
#endif
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 = pu16Translatebuffer;
if(is_Epaper_Write_Ready())
{
DPRINTK("\nEpaper Progress %d",percent);
//Epaper_Disp(stDisFrame);
auofb_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);
thread_active = 0;
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);
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);
#if defined(EPD_ENABLE_PRE_DISPLAY)
/*********************************************************/
if( AUO_EPAPER_CMD_INIT == r_partial_info.u16EpaperCommand )
{
#ifdef EPD_HW_ROTATE
Epaper_Init(AUO_EPAPER_PHYSICAL_H_RESOLUTION, AUO_EPAPER_PHYSICAL_V_RESOLUTION, 0, 0, 90, 0, 0, 0, 0, 0);
#else
Epaper_Init(AUO_EPAPER_PHYSICAL_H_RESOLUTION, AUO_EPAPER_PHYSICAL_V_RESOLUTION, 0, 0, 0, 0, 0, 0, 0, 0);
#endif
continue;
}
/*********************************************************/
#endif
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, 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<r_partial_info.h;i++)
{
memcpy(pu8Tmp_region+(i * r_partial_info.w * 2), pu8Tmp_copy_ptr, r_partial_info.w * 2);
pu8Tmp_copy_ptr = pu8Tmp_copy_ptr + H_RESOLUTION*2;
test_len = test_len + r_partial_info.w * 2;
}
DPRINTK("\nCopy Len 1 =%d\n",test_len);
//rotate
auofb_rotate_RGB565(r_partial_info.w, r_partial_info.h, (unsigned short*)
pu8Tmp_region, (unsigned short*)pu8RotateBuffer);
vfree(pu8Tmp_region);
}
DPRINTK("AUO EINK time rotate, jiffies: %lu, Elapsed time: %lu\n", jiffies, jiffies-tmp_clock);
tmp_clock = jiffies;
pu16ProcessPtr = (unsigned short*)pu8RotateBuffer;
auofb_convert_RGB565(r_partial_info.w, r_partial_info.h, (unsigned short*)pu8RotateBuffer, pu16Translatebuffer);
if(isInitial)
{
stDisFrame.u16EpaperCommand = r_partial_info.u16EpaperCommand;
stDisFrame.tFrameRange.X = r_partial_info.y + 1;
stDisFrame.tFrameRange.Y = (H_RESOLUTION - (r_partial_info.x) - r_partial_info.w) +1;
stDisFrame.tFrameRange.W = r_partial_info.h;
stDisFrame.tFrameRange.H = r_partial_info.w;
stDisFrame.pFrameData = pu16Translatebuffer;
if(is_Epaper_Write_Ready())
auofb_Disp(stDisFrame);
if( (u16PrevMode != PARTIAL_DSP_MODE_4) && (u16PrevMode != PARTIAL_DSP_MODE_4_W) )
{
if((r_partial_info.mode == PARTIAL_DSP_MODE_4) || (r_partial_info.mode == PARTIAL_DSP_MODE_4_W))
{
if(is_Epaper_Write_Ready())
auofb_Disp(stDisFrame);
}
}
u16PrevMode = r_partial_info.mode;
update_ready = false;
}
}
else
{
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, 90, 0, 0, 0, 0, 0);
}
#endif //#ifdef EPD_HW_ROTATE_NO_MODE4
if( (r_partial_info.w == auo_mach_info.xres_virtual) && (r_partial_info.h == auo_mach_info.yres_virtual))
{
auofb_convert_RGB565(r_partial_info.w, r_partial_info.h, (unsigned short*)pu8Framebuffer, pu16Translatebuffer);
}
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<r_partial_info.h;i++)
{
//memcpy(pu8Tmp_region+(i * r_partial_info.w * 2), pu8Tmp_copy_ptr, r_partial_info.w * 2);
memcpy(pu8RotateBuffer+(i * r_partial_info.w * 2), pu8Tmp_copy_ptr, r_partial_info.w * 2);
pu8Tmp_copy_ptr = pu8Tmp_copy_ptr + H_RESOLUTION*2;
test_len = test_len + r_partial_info.w * 2;
}
DPRINTK("\nCopy Len 1 =%d\n",test_len);
//rotate
/*auofb_rotate_RGB565(r_partial_info.w, r_partial_info.h, (unsigned short*)
pu8Tmp_region, (unsigned short*)pu8RotateBuffer);*/
//vfree(pu8Tmp_region);
pu16ProcessPtr = (unsigned short*)pu8RotateBuffer;
auofb_convert_RGB565(r_partial_info.w, r_partial_info.h, (unsigned short*)pu8RotateBuffer, pu16Translatebuffer);
}
if(isInitial)
{
stDisFrame.u16EpaperCommand = r_partial_info.u16EpaperCommand;
{
stDisFrame.tFrameRange.X = r_partial_info.x+1;
stDisFrame.tFrameRange.Y = r_partial_info.y+1;
stDisFrame.tFrameRange.W = r_partial_info.w;
stDisFrame.tFrameRange.H = r_partial_info.h;
}
stDisFrame.pFrameData = pu16Translatebuffer;
//stDisFrame.pFrameData = (unsigned short*)pu8Framebuffer; //do not need to convert
gStDisFrame = stDisFrame;
if(is_Epaper_Write_Ready())
auofb_Disp(stDisFrame);
if( (u16PrevMode != PARTIAL_DSP_MODE_4) && (u16PrevMode != PARTIAL_DSP_MODE_4_W) )
{
if((r_partial_info.mode == PARTIAL_DSP_MODE_4) || (r_partial_info.mode == PARTIAL_DSP_MODE_4_W))
{
if(is_Epaper_Write_Ready())
auofb_Disp(stDisFrame);
}
}
u16PrevMode = r_partial_info.mode;
update_ready = false;
DPRINTK("AUO EINK time display, jiffies: %lu, Elapsed time: %lu\n", jiffies, jiffies-tmp_clock);
tmp_clock = jiffies;
}
#ifdef EPD_HW_ROTATE_NO_MODE4
}
#endif
#else //sw rotate
#ifdef AUOFB_ROTATE
//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<r_partial_info.h;i++)
{
memcpy(pu8Tmp_region+(i * r_partial_info.w * 2), pu8Tmp_copy_ptr, r_partial_info.w * 2);
pu8Tmp_copy_ptr = pu8Tmp_copy_ptr + H_RESOLUTION*2;
test_len = test_len + r_partial_info.w * 2;
}
DPRINTK("\nCopy Len 1 =%d\n",test_len);
//rotate
auofb_rotate_RGB565(r_partial_info.w, r_partial_info.h, (unsigned short*)
pu8Tmp_region, (unsigned short*)pu8RotateBuffer);
vfree(pu8Tmp_region);
}
DPRINTK("AUO EINK time rotate, jiffies: %lu, Elapsed time: %lu\n", jiffies, jiffies-tmp_clock);
tmp_clock = jiffies;
#endif
#ifdef AUOFB_ROTATE
pu16ProcessPtr = (unsigned short*)pu8RotateBuffer;
#else
pu16ProcessPtr = (unsigned short*)pu8Framebuffer;
#endif
#ifdef AUOFB_ROTATE
auofb_convert_RGB565(r_partial_info.w, r_partial_info.h, (unsigned short*)pu8RotateBuffer, pu16Translatebuffer);
#else
auofb_convert_RGB565(r_partial_info.w, r_partial_info.h, (unsigned short*)pu8Framebuffer, pu16Translatebuffer);
#endif
DPRINTK("AUO EINK time convert grey, jiffies: %lu, Elapsed time: %lu\n", jiffies, jiffies-tmp_clock);
tmp_clock = jiffies;
if(isInitial)
{
//DPRINTK("\n@@@@@@@@@@@@send i80...");
//stDisFrame.u16EpaperCommand = AUO_EPAPER_CMD_FULLDISP;
stDisFrame.u16EpaperCommand = r_partial_info.u16EpaperCommand;
/*
if(r_partial_info.mode == 0)
{
stDisFrame.tFrameRange.X = 1;
stDisFrame.tFrameRange.Y = 1;
//stDisFrame.tFrameRange.W = H_RESOLUTION;
//stDisFrame.tFrameRange.H = V_RESOLUTION;
//rotation test: still send 800x600
stDisFrame.tFrameRange.W = 800;
stDisFrame.tFrameRange.H = 600;
}
else*/
{
#ifdef AUOFB_ROTATE
stDisFrame.tFrameRange.X = r_partial_info.y + 1;
stDisFrame.tFrameRange.Y = (H_RESOLUTION - (r_partial_info.x) - r_partial_info.w) +1;
stDisFrame.tFrameRange.W = r_partial_info.h;
stDisFrame.tFrameRange.H = r_partial_info.w;
#else
stDisFrame.tFrameRange.X = r_partial_info.x;
stDisFrame.tFrameRange.Y = r_partial_info.y;
stDisFrame.tFrameRange.W = r_partial_info.w;
stDisFrame.tFrameRange.H = r_partial_info.h;
#endif
}
stDisFrame.pFrameData = pu16Translatebuffer;
//stDisFrame.pFrameData = (unsigned short*)pu8Framebuffer; //do not need to convert
gStDisFrame = stDisFrame;
if(is_Epaper_Write_Ready())
auofb_Disp(stDisFrame);
if( (u16PrevMode != PARTIAL_DSP_MODE_4) && (u16PrevMode != PARTIAL_DSP_MODE_4_W) )
{
if((r_partial_info.mode == PARTIAL_DSP_MODE_4) || (r_partial_info.mode == PARTIAL_DSP_MODE_4_W))
{
if(is_Epaper_Write_Ready())
auofb_Disp(stDisFrame);
}
}
u16PrevMode = r_partial_info.mode;
update_ready = false;
DPRINTK("AUO EINK time display, jiffies: %lu, Elapsed time: %lu\n", jiffies, jiffies-tmp_clock);
tmp_clock = jiffies;
}
#endif //#ifdef EPD_HW_ROTATE
if(stDisFrame.u16EpaperCommand != AUO_EPAPER_CMD_PRE_DISPLAY_START)
{
if((r_partial_info.mode == PARTIAL_DSP_MODE_4) || (r_partial_info.mode == PARTIAL_DSP_MODE_4_W))
msleep(20);
else
msleep(500);
}
//printk("pw=%d, pr=%d\n",pw,pr);
}
DPRINTK("AUO EINK time end: %lu, Total Elapsed time: %lu\n", jiffies, jiffies-total_clock);
LOCK_AUOFB_EXIT();
}
//interruptible_sleep_on_timeout(&update_display_wq, 1500);
interruptible_sleep_on(&update_display_wq);
}
else
thread_active = 0;
}
complete_and_exit(&update_display_thread_exited, 0);
}
static void start_boot_progress_bar_thread(void)
{
return;
init_waitqueue_head(&boot_progress_bar_wq);
if ( 0 > (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)
{
return;
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)
{
return;
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)
{
return;
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)
{
return;
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)
{
return;
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 < UPDATE_WIDTH_MIN)
w_partial_info.h = UPDATE_WIDTH_MIN;
if((w_partial_info.h % UPDATE_WIDTH_MULTIPLES) != 0) //In EPD view, w is not times of UPDATE_WIDTH_MULTIPLES
{
DPRINTK("\nw_partial_info.h=%d\n",w_partial_info.h);
int tmp_offset = UPDATE_WIDTH_MULTIPLES - w_partial_info.h%UPDATE_WIDTH_MULTIPLES;
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 < UPDATE_HEIGHT_MIN)
w_partial_info.w = UPDATE_HEIGHT_MIN;
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 % UPDATE_HEIGHT_MULTIPLES) != 0) //In EPD view, h is not times of UPDATE_HEIGHT_MULTIPLES
{
DPRINTK("\nw_partial_info.w=%d\n",w_partial_info.w);
int tmp_offset = UPDATE_HEIGHT_MULTIPLES - w_partial_info.w%UPDATE_HEIGHT_MULTIPLES;
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 < UPDATE_HEIGHT_MIN) ||
(w_partial_info.w < UPDATE_WIDTH_MIN) ||
((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 % UPDATE_WIDTH_MULTIPLES) != 0) ||
((w_partial_info.w % UPDATE_HEIGHT_MULTIPLES) != 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
printk("\nAUOFB: Check coordinator"); //do not remove this printk
//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.w < UPDATE_WIDTH_MIN)
w_partial_info.w = UPDATE_WIDTH_MIN;
if((w_partial_info.w % UPDATE_WIDTH_MULTIPLES) != 0) //w is not times of UPDATE_WIDTH_MULTIPLES
{
DPRINTK("\nw_partial_info.w=%d\n",w_partial_info.w);
int tmp_offset = UPDATE_WIDTH_MULTIPLES - w_partial_info.w%UPDATE_WIDTH_MULTIPLES;
w_partial_info.w = w_partial_info.w + tmp_offset;
}
//test end
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 < UPDATE_HEIGHT_MIN)
w_partial_info.h = UPDATE_HEIGHT_MIN;
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.h % UPDATE_HEIGHT_MULTIPLES) != 0) //h is not times of UPDATE_HEIGHT_MULTIPLES
{
DPRINTK("\nw_partial_info.h=%d\n",w_partial_info.h);
int tmp_offset = UPDATE_HEIGHT_MULTIPLES - w_partial_info.h%UPDATE_HEIGHT_MULTIPLES;
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 < UPDATE_WIDTH_MIN) ||
(w_partial_info.h < UPDATE_HEIGHT_MIN) ||
((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 %UPDATE_WIDTH_MULTIPLES) != 0) ||
// ((w_partial_info.h % 2) != 0)
((w_partial_info.h % UPDATE_HEIGHT_MULTIPLES) != 0)
)
{
printk("\nAUOFB ERROR 111: (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 < UPDATE_WIDTH_MIN)
w_partial_info.h = UPDATE_WIDTH_MIN;
if((w_partial_info.h % UPDATE_WIDTH_MULTIPLES) != 0) //In EPD view, w is not times of UPDATE_WIDTH_MULTIPLES
{
DPRINTK("\nw_partial_info.h=%d\n",w_partial_info.h);
int tmp_offset = UPDATE_WIDTH_MULTIPLES - w_partial_info.h%UPDATE_WIDTH_MULTIPLES;
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 < UPDATE_HEIGHT_MIN)
w_partial_info.w = UPDATE_HEIGHT_MIN;
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 % UPDATE_HEIGHT_MULTIPLES) != 0) //In EPD view, h is not times of 2
{
DPRINTK("\nw_partial_info.w=%d\n",w_partial_info.w);
int tmp_offset = UPDATE_HEIGHT_MULTIPLES - w_partial_info.w%UPDATE_HEIGHT_MULTIPLES;
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 < UPDATE_WIDTH_MIN) ||
(w_partial_info.w < UPDATE_HEIGHT_MIN) ||
((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 % UPDATE_WIDTH_MULTIPLES) != 0) ||
((w_partial_info.w % UPDATE_HEIGHT_MULTIPLES) != 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;
}
#ifdef EPD_ENABLE_PRE_DISPLAY
int auo_fb_pre_display(void)
{
if ( 0 == LOCK_AUOFB_ENTRY() )
{
_partial_update_info tmp_partial_info;
tmp_partial_info.x = 0;
tmp_partial_info.y = 0;
tmp_partial_info.w = H_RESOLUTION;
tmp_partial_info.h = V_RESOLUTION;
tmp_partial_info.mode = 0;
tmp_partial_info.u16EpaperCommand = AUO_EPAPER_CMD_PRE_DISPLAY_START;
Epaper_Set_Partial_Update_Mode(tmp_partial_info.mode);
if(!auofb_update_queue_is_full())
auofb_update_queue_put(tmp_partial_info);
LOCK_AUOFB_EXIT();
}
// don't wakeup display thread.
//wake_update_display_thread(); w
//printk("\nauo_fb_pre_display\n");
}
#endif
#if defined(EPD_ENABLE_PRE_DISPLAY)
/*****************************************************************************/
void auo_fb_put_epd_init_command(void)
{
// printk("*** +%s\n", __func__);
if ( 0 == LOCK_AUOFB_ENTRY() )
{
_partial_update_info tmp_partial_info;
tmp_partial_info.x = 0;
tmp_partial_info.y = 0;
tmp_partial_info.w = 0;
tmp_partial_info.h = 0;
tmp_partial_info.mode = 0;
tmp_partial_info.u16EpaperCommand = AUO_EPAPER_CMD_INIT;
if(!auofb_update_queue_is_full())
{
// printk("*** %s: put init command\n", __func__);
auofb_update_queue_put(tmp_partial_info);
}
LOCK_AUOFB_EXIT();
}
// printk("*** -%s\n", __func__);
}
/*****************************************************************************/
#endif
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);
w_partial_info.u16EpaperCommand = AUO_EPAPER_CMD_PARTIALDISP;
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);
w_partial_info.u16EpaperCommand = AUO_EPAPER_CMD_PARTIALDISP;
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
if(is_Epaper_Write_Ready())
{
//AUO T-CON Standby
msleep(100);
Epaper_Enter_Standby_Mode(1);
msleep(100);
//AUO T-CON Sleep
Epaper_Enter_Sleep_Mode(1);
msleep(5);
//Shutdown T-CON Power
Epaper_Power(0);
//Shutdown i80 of s3c
EPaper_CloseLcdPort();
//msleep(1000);
u32PowerState = EN_EPD_DEVICE_POWER_STATE_D3;
}
else
return -EFAULT;
break;
case AUOFB_IOCTL_TCON_STANDBY: //TCON Standby
if(u32PowerState == EN_EPD_DEVICE_POWER_STATE_D0)
{
if(is_Epaper_Write_Ready())
{
msleep(100);
Epaper_Enter_Standby_Mode(1);
msleep(100); //TCON need at least 64ms to enter standby mode
u32PowerState = EN_EPD_DEVICE_POWER_STATE_D1;
}
else
return -EFAULT;
}
break;
case AUOFB_IOCTL_TCON_WAKEUP: //TCON Wakeup (leave standby)
if(u32PowerState == EN_EPD_DEVICE_POWER_STATE_D1)
{
Epaper_Enter_Standby_Mode(0);
msleep(100);
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);
msleep(5);
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);
msleep(5);
u32PowerState = EN_EPD_DEVICE_POWER_STATE_D1;
}
break;
case AUOFB_IOCTL_TCON_REFRESH: //Display refresh
if(is_Epaper_Write_Ready())
Epaper_Display_Refresh();
else
return -EFAULT;
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(lut_data == NULL)
{
return -EFAULT;
}
if(copy_from_user(lut_data, (unsigned char*) arg, AUO_LUT_LENGTH))
{
free_pages((unsigned long)lut_data, get_order(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:
if(is_Epaper_Write_Ready())
{
msleep(100);
Epaper_Enter_Standby_Mode(1);
msleep(100); //TCON need at least 64ms to enter standby mode
}
else
return -EFAULT;
break;
case EN_EPD_DEVICE_POWER_STATE_D2:
if(is_Epaper_Write_Ready())
{
//AUO T-CON Standby
msleep(100);
Epaper_Enter_Standby_Mode(1);
msleep(100);
//AUO T-CON Sleep
Epaper_Enter_Sleep_Mode(1);
msleep(5);
}
else
return -EFAULT;
break;
case EN_EPD_DEVICE_POWER_STATE_D3:
if(is_Epaper_Write_Ready())
{
//AUO T-CON Standby
msleep(100);
Epaper_Enter_Standby_Mode(1);
msleep(100);
//AUO T-CON Sleep
Epaper_Enter_Sleep_Mode(1);
msleep(5);
//Shutdown T-CON Power
Epaper_Power(0);
//Shutdown i80 of s3c
EPaper_CloseLcdPort();
//msleep(1000);
}
else
return -EFAULT;
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);
msleep(100);
break;
case EN_EPD_DEVICE_POWER_STATE_D1:
//do nothing
break;
case EN_EPD_DEVICE_POWER_STATE_D2:
Epaper_Enter_Sleep_Mode(1);
msleep(5);
break;
case EN_EPD_DEVICE_POWER_STATE_D3:
Epaper_Enter_Sleep_Mode(1);
msleep(5);
//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);
msleep(5);
Epaper_Enter_Standby_Mode(0);
msleep(100);
break;
case EN_EPD_DEVICE_POWER_STATE_D1:
Epaper_Enter_Sleep_Mode(0);
msleep(5);
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:
msleep(100);
#ifdef EPD_HW_ROTATE
Epaper_Init(AUO_EPAPER_PHYSICAL_H_RESOLUTION, AUO_EPAPER_PHYSICAL_V_RESOLUTION, 0, 0, 90, 0, 0, 0, 0, 0);
#else
Epaper_Init(AUO_EPAPER_PHYSICAL_H_RESOLUTION, AUO_EPAPER_PHYSICAL_V_RESOLUTION, 0, 0, 0, 0, 0, 0, 0, 0);
#endif
#ifdef EPD_ENABLE_PRE_DISPLAY
atomic_set(&gPowerOnFirstDisplay, 1);
auo_fb_pre_display();
#endif
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;
}
/* Qisda, Howard Hsu, 2010/01/11, Add show image ioctrl { */
case AUOFB_IOCTL_SHOW_IMAGE:
{
T_DISPLAY_FRAME stDisFrame;
_partial_update_info partial_info;
unsigned long pic_array_size = 0;
unsigned long pic_array_max = AUO_EPAPER_PHYSICAL_H_RESOLUTION*AUO_EPAPER_PHYSICAL_V_RESOLUTION/2;
unsigned char *pic_array = vmalloc(pic_array_max, GFP_KERNEL);
if(copy_from_user(&partial_info, (_partial_update_info *) arg, sizeof(_partial_update_info)))
return -EFAULT;
if(copy_from_user(&pic_array_size, (unsigned long*) ((char *)arg+sizeof(_partial_update_info)), sizeof(unsigned long)))
return -EFAULT;
if(copy_from_user(pic_array, (char*) ((char *)arg+sizeof(_partial_update_info)+sizeof(unsigned long)), pic_array_size))
return -EFAULT;
stDisFrame.u16EpaperCommand = AUO_EPAPER_CMD_PARTIALDISP;
Epaper_Set_Partial_Update_Mode(partial_info.mode);
stDisFrame.tFrameRange.W = partial_info.w;
stDisFrame.tFrameRange.H = partial_info.h;
stDisFrame.tFrameRange.X = partial_info.x;
stDisFrame.tFrameRange.Y = partial_info.y;
if ( partial_info.x==0 || partial_info.y==0)
{
stDisFrame.tFrameRange.X = (H_RESOLUTION-partial_info.w)/2;
stDisFrame.tFrameRange.Y = (V_RESOLUTION-partial_info.h)/2;
if((stDisFrame.tFrameRange.X % 2) == 0)
stDisFrame.tFrameRange.X ++;
if((stDisFrame.tFrameRange.Y % 2) == 0)
stDisFrame.tFrameRange.Y ++;
}
stDisFrame.pFrameData = (unsigned short*)pic_array;
if(is_Epaper_Write_Ready())
{
printk("Show Image on EPD\n");
Epaper_Disp(stDisFrame);
}
else
{
printk("EPD not ready to show Image\n");
}
vfree(pic_array);
break;
}
/* } Qisda, Howard Hsu, 2010/01/11, Add show image ioctrl */
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
#ifdef EPD_HW_ROTATE
//Epaper_Reset();
Epaper_Init(AUO_EPAPER_PHYSICAL_H_RESOLUTION, AUO_EPAPER_PHYSICAL_V_RESOLUTION, 0, 0, 90, 0, 0, 0, 0, 0);
#else
//Epaper_Reset();
Epaper_Init(AUO_EPAPER_PHYSICAL_H_RESOLUTION, AUO_EPAPER_PHYSICAL_V_RESOLUTION, 0, 0, 0, 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);
#ifdef FRAMEBUFFER_DMA
if (!request_mem_region((unsigned long)S3C24XX_VA_LCD, SZ_1M, "s3c-lcd")) {
ret = -EBUSY;
return ret;
}
auofb_basic_display_setting(0,0);
#endif
/*
* Dynamically allocate info and par
*/
//pu8Framebuffer = vmalloc(800*600*3);
///pu8Framebuffer = vmalloc(info.fb.fix.smem_len);
pu8Framebuffer = vmalloc(V_RESOLUTION*H_RESOLUTION*2);
#ifdef FRAMEBUFFER_DMA
pu16Translatebuffer = cpu_VideoPhysicalTemp_f1;
#else
pu16Translatebuffer = vmalloc(V_RESOLUTION*H_RESOLUTION/2);
#endif
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);
/* The TCON MUST be inited before anythings! We can't wait for the
* bootloader to do all the things for us!! */
Epaper_SetLcdPort();
/*
* 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
w_partial_info.u16EpaperCommand = AUO_EPAPER_CMD_PARTIALDISP;
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();
#ifdef CONFIG_LOGO_LINUX_SH060B00_6_INCH_CLUT224
#else
//start_boot_progress_bar_thread();
#endif
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);
#ifdef FRAMEBUFFER_DMA
dma_free_writecombine(((struct auo_fb_info *)&info[index])->dev, H_RESOLUTION*V_RESOLUTION/2, cpu_VideoPhysicalTemp_f1, map_VideoPhysicalTemp_f1);
release_mem_region((unsigned long)S3C24XX_VA_LCD, S3C24XX_SZ_LCD);
#else
vfree(pu16Translatebuffer);
#endif
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 1
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
msleep(100);
Epaper_Enter_Standby_Mode(1);
msleep(100);
//AUO T-CON Sleep
Epaper_Enter_Sleep_Mode(1);
msleep(5);
//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;
#else
//EPaper_CloseLcdPort();
return 0;
#endif
}
static int auofb_resume(struct platform_device *dev)
{
Epaper_SetLcdPort();
#if 0
DPRINTK("\nAUOFB Resume");
//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;
#if defined(EPD_ENABLE_PRE_DISPLAY)
auo_fb_put_epd_init_command();
#else
#ifdef EPD_HW_ROTATE
Epaper_Init(AUO_EPAPER_PHYSICAL_H_RESOLUTION, AUO_EPAPER_PHYSICAL_V_RESOLUTION, 0, 0, 90, 0, 0, 0, 0, 0);
#else
Epaper_Init(AUO_EPAPER_PHYSICAL_H_RESOLUTION, AUO_EPAPER_PHYSICAL_V_RESOLUTION, 0, 0, 0, 0, 0, 0, 0, 0);
#endif
#endif
#ifdef EPD_ENABLE_PRE_DISPLAY
atomic_set(&gPowerOnFirstDisplay, 1);
auo_fb_pre_display();
#endif
#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");