您的位置:首页 > Web前端

s3c6410_LCD & frame buffer 驱动分析(二)

2011-11-22 00:59 435 查看
/*

*初始化LCD控制寄存器

*/

int s3cfb_init_registers(s3cfb_info_t *fbi)

{

struct clk *lcd_clock;

struct fb_var_screeninfo *var = &fbi->fb.var;

unsigned long flags = 0, page_width = 0, offset = 0;

unsigned long video_phy_temp_f1 = fbi->screen_dma_f1;//物理地址

unsigned long video_phy_temp_f2 = fbi->screen_dma_f2;//物理地址

int win_num = fbi->win_id;//5个窗口

//关闭中断在写LCD控制寄存器之前,并保存中断状态

local_irq_save(flags);

//显示宽度,以字节为单位

page_width = var->xres * s3cfb_fimd.bytes_per_pixel;

//虚拟到可见区域的偏移量,以字节为单位

offset = (var->xres_virtual - var->xres) * s3cfb_fimd.bytes_per_pixel;

if (win_num == 0) {

//在配置LCD控制器之前需要先关闭LCD视频输出

s3cfb_fimd.vidcon0 = s3cfb_fimd.vidcon0 & ~(S3C_VIDCON0_ENVID_ENABLE | S3C_VIDCON0_ENVID_F_ENABLE);

writel(s3cfb_fimd.vidcon0, S3C_VIDCON0);

//获取LCD时钟来源 Video Clock Source is selected by CLKSEL_F registe

lcd_clock = clk_get(NULL, "lcd");

//计算VCLK = lcd_clock / (CLKVAL+1)

s3cfb_fimd.vidcon0 |= S3C_VIDCON0_CLKVAL_F((int) ((clk_get_rate(lcd_clock) / s3cfb_fimd.pixclock) - 1));

#if defined(CONFIG_FB_S3C_EXT_VIRTUAL_SCREEN)

offset = 0;//将虚拟到可见区域的偏移量设置成0

//Window 0’s buffer start address register, buffer 0

s3cfb_fimd.vidw00add0b0 = video_phy_temp_f1;

//Window 0’s buffer start address register, buffer 1

s3cfb_fimd.vidw00add0b1 = video_phy_temp_f2;

//Window 1’s buffer start address register, buffer 0

s3cfb_fimd.vidw00add1b0 = S3C_VIDWxxADD1_VBASEL_F((unsigned long) video_phy_temp_f1 + (page_width + offset) * (var->yres));

//Window 1’s buffer start address register, buffer 1

s3cfb_fimd.vidw00add1b1 = S3C_VIDWxxADD1_VBASEL_F((unsigned long) video_phy_temp_f2 + (page_width + offset) * (var->yres));

#endif

}

//各窗口起始地址

writel(video_phy_temp_f1, S3C_VIDW00ADD0B0 + (0x08 * win_num));

//各窗口结束地址

writel(S3C_VIDWxxADD1_VBASEL_F((unsigned long) video_phy_temp_f1 + (page_width + offset) * (var->yres)), S3C_VIDW00ADD1B0 + (0x08 * win_num));

// Virtual screen offset size (the number of byte).

writel(S3C_VIDWxxADD2_OFFSIZE_F(offset) | (S3C_VIDWxxADD2_PAGEWIDTH_F(page_width)), S3C_VIDW00ADD2 + (0x04 * win_num));

if (win_num < 2) {

writel(video_phy_temp_f2, S3C_VIDW00ADD0B1 + (0x08 * win_num));

writel(S3C_VIDWxxADD1_VBASEL_F((unsigned long) video_phy_temp_f2 + (page_width + offset) * (var->yres)), S3C_VIDW00ADD1B1 + (0x08 * win_num));

}

//上面这些操作可以对照S3C6410手册照着填写

switch (win_num) {

//将配置好的值都写入个寄存器当中

case 0:

writel(s3cfb_fimd.wincon0, S3C_WINCON0);

writel(s3cfb_fimd.vidcon0, S3C_VIDCON0);

writel(s3cfb_fimd.vidcon1, S3C_VIDCON1);

writel(s3cfb_fimd.vidtcon0, S3C_VIDTCON0);

writel(s3cfb_fimd.vidtcon1, S3C_VIDTCON1);

writel(s3cfb_fimd.vidtcon2, S3C_VIDTCON2);

writel(s3cfb_fimd.dithmode, S3C_DITHMODE);

writel(s3cfb_fimd.vidintcon0, S3C_VIDINTCON0);

writel(s3cfb_fimd.vidintcon1, S3C_VIDINTCON1);

writel(s3cfb_fimd.vidosd0a, S3C_VIDOSD0A);

writel(s3cfb_fimd.vidosd0b, S3C_VIDOSD0B);

writel(s3cfb_fimd.vidosd0c, S3C_VIDOSD0C);

writel(s3cfb_fimd.wpalcon, S3C_WPALCON);

s3cfb_onoff_win(fbi, ON);

break;

case 1:

writel(s3cfb_fimd.wincon1, S3C_WINCON1);

writel(s3cfb_fimd.vidosd1a, S3C_VIDOSD1A);

writel(s3cfb_fimd.vidosd1b, S3C_VIDOSD1B);

writel(s3cfb_fimd.vidosd1c, S3C_VIDOSD1C);

writel(s3cfb_fimd.vidosd1d, S3C_VIDOSD1D);

writel(s3cfb_fimd.wpalcon, S3C_WPALCON);

s3cfb_onoff_win(fbi, OFF);

break;

case 2:

writel(s3cfb_fimd.wincon2, S3C_WINCON2);

writel(s3cfb_fimd.vidosd2a, S3C_VIDOSD2A);

writel(s3cfb_fimd.vidosd2b, S3C_VIDOSD2B);

writel(s3cfb_fimd.vidosd2c, S3C_VIDOSD2C);

writel(s3cfb_fimd.vidosd2d, S3C_VIDOSD2D);

writel(s3cfb_fimd.wpalcon, S3C_WPALCON);

s3cfb_onoff_win(fbi, OFF);

break;

case 3:

writel(s3cfb_fimd.wincon3, S3C_WINCON3);

writel(s3cfb_fimd.vidosd3a, S3C_VIDOSD3A);

writel(s3cfb_fimd.vidosd3b, S3C_VIDOSD3B);

writel(s3cfb_fimd.vidosd3c, S3C_VIDOSD3C);

writel(s3cfb_fimd.wpalcon, S3C_WPALCON);

s3cfb_onoff_win(fbi, OFF);

break;

case 4:

writel(s3cfb_fimd.wincon4, S3C_WINCON4);

writel(s3cfb_fimd.vidosd4a, S3C_VIDOSD4A);

writel(s3cfb_fimd.vidosd4b, S3C_VIDOSD4B);

writel(s3cfb_fimd.vidosd4c, S3C_VIDOSD4C);

writel(s3cfb_fimd.wpalcon, S3C_WPALCON);

s3cfb_onoff_win(fbi, OFF);

break;

}

//开启中断

local_irq_restore(flags);

return 0;

}

//下面可以分析framebuffer提供给应用层的函数操作指针了

struct fb_ops s3cfb_ops = {

.owner = THIS_MODULE,

.fb_check_var = s3cfb_check_var,//检测可变参数,并调整到支持的值

.fb_set_par = s3cfb_set_par, //设置video的模式

.fb_blank = s3cfb_blank, //显示空白区域

.fb_pan_display = s3cfb_pan_display,//pan显示

.fb_setcolreg = s3cfb_setcolreg,//设置color寄存器,设置颜色表

.fb_fillrect = cfb_fillrect, //矩形填充

.fb_copyarea = cfb_copyarea, //数据复制

.fb_imageblit = cfb_imageblit, //图形填充

.fb_cursor = soft_cursor, //绘制光标

.fb_ioctl = s3cfb_ioctl, //fb特定的ioctl

};

这里只贴s3cfb_ioctl的代码,其余的详情可以参见Linux内核源代码,另外值得注意的就是这些函数都可以使用默认内核默认的,fbmem.c中

int s3cfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)

{

s3cfb_info_t *fbi = container_of(info, s3cfb_info_t, fb);

s3cfb_win_info_t win_info;

s3cfb_color_key_info_t colkey_info;

s3cfb_color_val_info_t colval_info;

s3cfb_dma_info_t dma_info;

s3cfb_next_info_t next_fb_info;

struct fb_var_screeninfo *var= &fbi->fb.var;

unsigned int crt, alpha_level, alpha_mode;

#if defined(CONFIG_S3C6410_PWM)

int brightness;

#endif

#if defined(CONFIG_FB_S3C_EXT_DOUBLE_BUFFERING)

unsigned int f_num_val;

#endif

#if defined(CONFIG_FB_S3C_EXT_VIRTUAL_SCREEN)

s3cfb_vs_info_t vs_info;

#endif

switch(cmd){

case S3CFB_GET_INFO:

dma_info.map_dma_f1 = fbi->map_dma_f1;

dma_info.map_dma_f2 = fbi->map_dma_f2;

if(copy_to_user((void *) arg, (const void *) &dma_info, sizeof(s3cfb_dma_info_t)))

return -EFAULT;

break;

case S3CFB_OSD_SET_INFO:

if (copy_from_user(&win_info, (s3cfb_win_info_t *) arg, sizeof(s3cfb_win_info_t)))

return -EFAULT;

s3cfb_init_win(fbi, win_info.bpp, win_info.left_x, win_info.top_y, win_info.width, win_info.height, OFF);

break;

case S3CFB_OSD_START:

s3cfb_onoff_win(fbi, ON);

break;

case S3CFB_OSD_STOP:

s3cfb_onoff_win(fbi, OFF);

break;

case S3CFB_OSD_ALPHA_UP:

alpha_level = readl(S3C_VIDOSD0C + (0x10 * fbi->win_id)) & 0xf;

if (alpha_level < S3CFB_MAX_ALPHA_LEVEL)

alpha_level++;

s3cfb_set_alpha_level(fbi, alpha_level, 1);

break;

case S3CFB_OSD_ALPHA_DOWN:

alpha_level = readl(S3C_VIDOSD0C + (0x10 * fbi->win_id)) & 0xf;

if (alpha_level > 0)

alpha_level--;

s3cfb_set_alpha_level(fbi, alpha_level, 1);

break;

case S3CFB_OSD_ALPHA0_SET:

alpha_level = (unsigned int) arg;

if (alpha_level > S3CFB_MAX_ALPHA_LEVEL)

alpha_level = S3CFB_MAX_ALPHA_LEVEL;

s3cfb_set_alpha_level(fbi, alpha_level, 0);

break;

case S3CFB_OSD_ALPHA1_SET:

alpha_level = (unsigned int) arg;

if (alpha_level > S3CFB_MAX_ALPHA_LEVEL)

alpha_level = S3CFB_MAX_ALPHA_LEVEL;

s3cfb_set_alpha_level(fbi, alpha_level, 1);

break;

case S3CFB_OSD_ALPHA_MODE:

alpha_mode = (unsigned int) arg;

s3cfb_set_alpha_mode(fbi, alpha_mode);

break;

case S3CFB_OSD_MOVE_LEFT:

if (var->xoffset > 0)

var->xoffset--;

s3cfb_set_win_position(fbi, var->xoffset, var->yoffset, var->xres, var->yres);

break;

case S3CFB_OSD_MOVE_RIGHT:

if (var->xoffset < (s3cfb_fimd.width - var->xres))

var->xoffset++;

s3cfb_set_win_position(fbi, var->xoffset, var->yoffset, var->xres, var->yres);

break;

case S3CFB_OSD_MOVE_UP:

if (var->yoffset > 0)

var->yoffset--;

s3cfb_set_win_position(fbi, var->xoffset, var->yoffset, var->xres, var->yres);

break;

case S3CFB_OSD_MOVE_DOWN:

if (var->yoffset < (s3cfb_fimd.height - var->yres))

var->yoffset++;

s3cfb_set_win_position(fbi, var->xoffset, var->yoffset, var->xres, var->yres);

break;

case FBIO_WAITFORVSYNC:

if (get_user(crt, (unsigned int __user *)arg))

return -EFAULT;

return s3cfb_wait_for_vsync();

case S3CFB_COLOR_KEY_START:

s3cfb_onoff_color_key(fbi, ON);

break;

case S3CFB_COLOR_KEY_STOP:

s3cfb_onoff_color_key(fbi, OFF);

break;

case S3CFB_COLOR_KEY_ALPHA_START:

s3cfb_onoff_color_key_alpha(fbi, ON);

break;

case S3CFB_COLOR_KEY_ALPHA_STOP:

s3cfb_onoff_color_key_alpha(fbi, OFF);

break;

case S3CFB_COLOR_KEY_SET_INFO:

if (copy_from_user(&colkey_info, (s3cfb_color_key_info_t *) arg, sizeof(s3cfb_color_key_info_t)))

return -EFAULT;

s3cfb_set_color_key_registers(fbi, colkey_info);

break;

case S3CFB_COLOR_KEY_VALUE:

if (copy_from_user(&colval_info, (s3cfb_color_val_info_t *) arg, sizeof(s3cfb_color_val_info_t)))

return -EFAULT;

s3cfb_set_color_value(fbi, colval_info);

break;

case S3CFB_SET_VSYNC_INT:

s3cfb_fimd.vidintcon0 &= ~S3C_VIDINTCON0_FRAMESEL0_MASK;

s3cfb_fimd.vidintcon0 |= S3C_VIDINTCON0_FRAMESEL0_VSYNC;

if (arg)

s3cfb_fimd.vidintcon0 |= S3C_VIDINTCON0_INTFRMEN_ENABLE;

else

s3cfb_fimd.vidintcon0 &= ~S3C_VIDINTCON0_INTFRMEN_ENABLE;

writel(s3cfb_fimd.vidintcon0, S3C_VIDINTCON0);

break;

case S3CFB_SET_NEXT_FB_INFO:

if (copy_from_user(&next_fb_info, (s3cfb_next_info_t *) arg, sizeof(s3cfb_next_info_t)))

return -EFAULT;

/* check arguments */

if ((next_fb_info.xres + next_fb_info.xoffset) > next_fb_info.xres_virtual ||

(next_fb_info.yres + next_fb_info.yoffset) > next_fb_info.yres_virtual ||

(next_fb_info.xres + next_fb_info.lcd_offset_x ) > s3cfb_fimd.width ||

(next_fb_info.yres + next_fb_info.lcd_offset_y ) > s3cfb_fimd.height) {

printk("Error : S3CFB_SET_NEXT_FB_INFO\n");

return -EINVAL;

}

fbi->next_fb_info = next_fb_info;

fbi->next_fb_info_change_req = 1;

break;

case S3CFB_GET_CURR_FB_INFO:

next_fb_info.phy_start_addr = fbi->fb.fix.smem_start;

next_fb_info.xres = fbi->fb.var.xres;

next_fb_info.yres = fbi->fb.var.yres;

next_fb_info.xres_virtual = fbi->fb.var.xres_virtual;

next_fb_info.yres_virtual = fbi->fb.var.yres_virtual;

next_fb_info.xoffset = fbi->fb.var.xoffset;

next_fb_info.yoffset = fbi->fb.var.yoffset;

next_fb_info.lcd_offset_x = fbi->lcd_offset_x;

next_fb_info.lcd_offset_y = fbi->lcd_offset_y;

if (copy_to_user((void *)arg, (s3cfb_next_info_t *) &next_fb_info, sizeof(s3cfb_next_info_t)))

return -EFAULT;

break;

case S3CFB_GET_BRIGHTNESS:

if (copy_to_user((void *)arg, (const void *) &s3cfb_fimd.brightness, sizeof(int)))

return -EFAULT;

break;

#if defined(CONFIG_S3C6410_PWM)

case S3CFB_SET_BRIGHTNESS:

if (copy_from_user(&brightness, (int *) arg, sizeof(int)))

return -EFAULT;

s3cfb_set_brightness(brightness);

break;

#endif

#if defined(CONFIG_FB_S3C_EXT_VIRTUAL_SCREEN)

case S3CFB_VS_START:

s3cfb_fimd.wincon0 &= ~(S3C_WINCONx_ENWIN_F_ENABLE);

writel(s3cfb_fimd.wincon0 | S3C_WINCONx_ENWIN_F_ENABLE, S3C_WINCON0);

fbi->fb.var.xoffset = s3cfb_fimd.xoffset;

fbi->fb.var.yoffset = s3cfb_fimd.yoffset;

break;

case S3CFB_VS_STOP:

s3cfb_fimd.vidw00add0b0 = fbi->screen_dma_f1;

s3cfb_fimd.vidw00add0b1 = fbi->screen_dma_f2;

fbi->fb.var.xoffset = 0;

fbi->fb.var.yoffset = 0;

writel(s3cfb_fimd.vidw00add0b0, S3C_VIDW00ADD0B0);

writel(s3cfb_fimd.vidw00add0b1, S3C_VIDW00ADD0B1);

break;

case S3CFB_VS_SET_INFO:

if (copy_from_user(&vs_info, (s3cfb_vs_info_t *) arg, sizeof(s3cfb_vs_info_t)))

return -EFAULT;

if (s3cfb_set_vs_info(vs_info)) {

printk("Error S3CFB_VS_SET_INFO\n");

return -EINVAL;

}

s3cfb_set_vs_registers(S3CFB_VS_SET);

fbi->fb.var.xoffset = s3cfb_fimd.xoffset;

fbi->fb.var.yoffset = s3cfb_fimd.yoffset;

break;

case S3CFB_VS_MOVE:

s3cfb_set_vs_registers(arg);

fbi->fb.var.xoffset = s3cfb_fimd.xoffset;

fbi->fb.var.yoffset = s3cfb_fimd.yoffset;

break;

#endif

#if defined(CONFIG_FB_S3C_EXT_DOUBLE_BUFFERING)

case S3CFB_GET_NUM:

if (copy_from_user((void *)&f_num_val, (const void *)arg, sizeof(u_int)))

return -EFAULT;

if (copy_to_user((void *)arg, (const void *) &f_num_val, sizeof(u_int)))

return -EFAULT;

break;

case S3CFB_CHANGE_REQ:

s3cfb_change_buff(0, (int) arg);

break;

#endif

default:

return -EINVAL;

}

return 0;

}

关于IOCTL中的命令的定义以及各命令当中的处理函数可以下载LCD驱动源码连接点击下载LCD驱动源码 这些命令都定义在s3cfb.h当中,另外值得注意的就是linux内核当中

提供给framebuffer的通用代码fbmem.c中的ioctl函数。当我们真正拿LCD来显示一些什么东西的时候那么熟悉这些ioctl函数是很有必要的,至少做的时候要值得在那个地方找
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: