linux中LCD设备驱动(5)——基于s3c6410平台

时间:2021-12-26 02:41:01

s3c6410硬件DISPLAY CONTROLLER(显示控制器)的地址链接

linux中LCD设备驱动(1)——framebuffer(帧缓冲)的地址链接

linux中LCD设备驱动(2)——基于s3c6410平台的地址链接

linux中LCD设备驱动(3)——基于s3c6410平台的地址链接

linux中LCD设备驱动(4)——基于s3c6410平台的地址链接


在前几篇中对LCD平台设备所对应的probe函数进行分析时,对一些函数没有进行详细的分析,因为当时主要是为了突出probe函数的整体结构,现在我们对一些函数进行再次详细点的分析。

(1)、

void s3cfb_pre_init(void)
{
/* initialize the fimd specific */
s3cfb_fimd.vidintcon0 &= ~S3C_VIDINTCON0_FRAMESEL0_MASK;
s3cfb_fimd.vidintcon0 |= S3C_VIDINTCON0_FRAMESEL0_VSYNC;
s3cfb_fimd.vidintcon0 |= S3C_VIDINTCON0_INTFRMEN_ENABLE;


writel(s3cfb_fimd.vidintcon0, S3C_VIDINTCON0);
}

这个函数主要是对VIDINTCON0寄存器的操作,这个寄存器和中断有关。具体的对那些位进行操作和怎样操作,查看手册就可以了。

linux中LCD设备驱动(5)——基于s3c6410平台

(2)、

这个函数的主要作用是填充s3cfb_info_t 结构体中的成员。
static void s3cfb_init_fbinfo(s3cfb_info_t *finfo, char *drv_name, int index)
{
int i = 0;


if (index == 0)
s3cfb_init_hw();这个函数我们在上一篇博客中详细讲了,主要是根据具体TFT屏幕的参数对LCD控制寄存器的一些寄存器进行设置,还有对全局量s3cfb_fimd结构体的填充。


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 = 1;
finfo->fb.fix.ywrapstep = 0;
finfo->fb.fix.accel = FB_ACCEL_NONE;


finfo->fb.fbops = &s3cfb_ops;  指向fb的操作函数集
finfo->fb.flags= FBINFO_FLAG_DEFAULT;


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 = s3cfb_fimd.xoffset;
finfo->fb.var.yoffset = s3cfb_fimd.yoffset;


if (index == 0) {    第一层窗口时的设置
finfo->fb.var.height = s3cfb_fimd.height;
finfo->fb.var.width = s3cfb_fimd.width;


finfo->fb.var.xres = s3cfb_fimd.xres;
finfo->fb.var.yres = s3cfb_fimd.yres;


finfo->fb.var.xres_virtual = s3cfb_fimd.xres_virtual;
finfo->fb.var.yres_virtual = s3cfb_fimd.yres_virtual;
} else {    其它层窗口的设置
finfo->fb.var.height = s3cfb_fimd.osd_height;
finfo->fb.var.width = s3cfb_fimd.osd_width;


finfo->fb.var.xres = s3cfb_fimd.osd_xres;
finfo->fb.var.yres = s3cfb_fimd.osd_yres;


finfo->fb.var.xres_virtual = s3cfb_fimd.osd_xres_virtual;
finfo->fb.var.yres_virtual = s3cfb_fimd.osd_yres_virtual;
}


finfo->fb.var.bits_per_pixel = s3cfb_fimd.bpp;
        finfo->fb.var.pixclock = s3cfb_fimd.pixclock;
finfo->fb.var.hsync_len = s3cfb_fimd.hsync_len;
finfo->fb.var.left_margin = s3cfb_fimd.left_margin;
finfo->fb.var.right_margin = s3cfb_fimd.right_margin;
finfo->fb.var.vsync_len = s3cfb_fimd.vsync_len;
finfo->fb.var.upper_margin = s3cfb_fimd.upper_margin;
finfo->fb.var.lower_margin = s3cfb_fimd.lower_margin;
finfo->fb.var.sync = s3cfb_fimd.sync;
finfo->fb.var.grayscale = s3cfb_fimd.cmap_grayscale;


finfo->fb.fix.smem_len = finfo->fb.var.xres_virtual * finfo->fb.var.yres_virtual * s3cfb_fimd.bytes_per_pixel;
finfo->fb.fix.line_length = finfo->fb.var.width * s3cfb_fimd.bytes_per_pixel;


#if !defined(CONFIG_FB_S3C_VIRTUAL_SCREEN)


#if defined(CONFIG_FB_S3C_DOUBLE_BUFFERING)
if (index < 2)
finfo->fb.fix.smem_len *= 2;
#else
/*
* Some systems(ex. DirectFB) use FB0 memory as a video memory.
* You can modify the size of multiple.
*/
if (index == 0)
finfo->fb.fix.smem_len *= 5;
#endif


#endif

for (i = 0; i < 256; i++)
finfo->palette_buffer[i] = S3CFB_PALETTE_BUFF_CLEAR;  清除缓冲区
}

(3)、
这个函数用来为显存分配内存
static int __init s3cfb_map_video_memory(s3cfb_info_t *fbi)
{
DPRINTK("map_video_memory(fbi=%p)\n", fbi);


fbi->map_size_f1 = PAGE_ALIGN(fbi->fb.fix.smem_len);
fbi->map_cpu_f1 = dma_alloc_writecombine(fbi->dev, fbi->map_size_f1, &fbi->map_dma_f1, GFP_KERNEL);

    //因为系统采用DMA来搬移显示数据,所以使用dma_alloc_writecombine来分配一段内存区域
fbi->map_size_f1 = fbi->fb.fix.smem_len;


if (fbi->map_cpu_f1) {   如果分配成功,对s3cfb_info_t结构体的某些成员,进行填充
/* prevent initial garbage on screen */
printk("Window[%d] - FB1: map_video_memory: clear %p:%08x\n",
fbi->win_id, fbi->map_cpu_f1, fbi->map_size_f1);
memset(fbi->map_cpu_f1, 0xf0, fbi->map_size_f1);


fbi->screen_dma_f1 = fbi->map_dma_f1;
fbi->fb.screen_base = fbi->map_cpu_f1;
fbi->fb.fix.smem_start = fbi->screen_dma_f1;


printk("            FB1: map_video_memory: dma=%08x cpu=%p size=%08x\n",
fbi->map_dma_f1, fbi->map_cpu_f1, fbi->fb.fix.smem_len);
}


if (!fbi->map_cpu_f1)
return -ENOMEM;


#if defined(CONFIG_FB_S3C_DOUBLE_BUFFERING)
if (fbi->win_id < 2 && fbi->map_cpu_f1) {
fbi->map_size_f2 = (fbi->fb.fix.smem_len / 2);
fbi->map_cpu_f2 = fbi->map_cpu_f1 + fbi->map_size_f2;
fbi->map_dma_f2 = fbi->map_dma_f1 + fbi->map_size_f2;


/* prevent initial garbage on screen */
printk("Window[%d] - FB2: map_video_memory: clear %p:%08x\n",
fbi->win_id, fbi->map_cpu_f2, fbi->map_size_f2);


fbi->screen_dma_f2 = fbi->map_dma_f2;


printk("            FB2: map_video_memory: dma=%08x cpu=%p size=%08x\n",
fbi->map_dma_f2, fbi->map_cpu_f2, fbi->map_size_f2);
}
#endif


if (s3cfb_fimd.map_video_memory)
(s3cfb_fimd.map_video_memory)(fbi);


return 0;
}

(4)、

/*
 * s3cfb_check_var():
 * Get the video params out of 'var'. If a value doesn't fit, round it up,
 * if it's too big, return -EINVAL.
 *
 */ 此函数检查fb_info中的可变参数。
static int s3cfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
s3cfb_info_t *fbi = (s3cfb_info_t *) info;


DPRINTK("check_var(var=%p, info=%p)\n", var, info);


switch (var->bits_per_pixel) {    BPP,每像素的位数
case 8:  8BPP
var->red = s3cfb_rgb_8.red;
var->green = s3cfb_rgb_8.green;
var->blue = s3cfb_rgb_8.blue;
var->transp = s3cfb_rgb_8.transp;
s3cfb_fimd.bytes_per_pixel = 1;
break;
其实上面这些red、green等都是 fb_bitfield 的结构体,这个结构体描述了每一像素显示缓冲区的组织方式,在第一篇博客说framebuffer中说过了。

struct fb_bitfield {
__u32 offset; /* beginning of bitfield */
__u32 length; /* length of bitfield */
__u32 msb_right;/* != 0 : Most significant bit is */ 
/* right */ 
};

其实在S3cfb.h (linux2.6.28\drivers\video\samsung)文件中还有如下定义:

typedef struct {
struct fb_bitfield red;
struct fb_bitfield green;
struct fb_bitfield blue;
struct fb_bitfield transp;
} s3cfb_rgb_t;


const static s3cfb_rgb_t s3cfb_rgb_8 = {
.red    = {.offset = 0,  .length = 8,},
.green  = {.offset = 0,  .length = 8,},
.blue   = {.offset = 0,  .length = 8,},
.transp = {.offset = 0,  .length = 0,},
};


const static s3cfb_rgb_t s3cfb_rgb_16 = {
.red    = {.offset = 11, .length = 5,},
.green  = {.offset = 5,  .length = 6,},
.blue   = {.offset = 0,  .length = 5,},
.transp = {.offset = 0,  .length = 0,},
};


const static s3cfb_rgb_t s3cfb_rgb_24 = {
.red    = {.offset = 16, .length = 8,},
.green  = {.offset = 8,  .length = 8,},
.blue   = {.offset = 0,  .length = 8,},
.transp = {.offset = 0,  .length = 0,},
};


const static s3cfb_rgb_t s3cfb_rgb_28 = {
.red    = {.offset = 16, .length = 8,},
.green  = {.offset = 8,  .length = 8,},
.blue   = {.offset = 0,  .length = 8,},
.transp = {.offset = 24,  .length = 4,},
};


const static s3cfb_rgb_t s3cfb_rgb_32 = {
.red    = {.offset = 16, .length = 8,},
.green  = {.offset = 8,  .length = 8,},
.blue   = {.offset = 0,  .length = 8,},
.transp = {.offset = 24, .length = 8,},
};

下面也是一样的,看到这些,我想一切尽在不言中了吧?
case 16:
var->red = s3cfb_rgb_16.red;
var->green = s3cfb_rgb_16.green;
var->blue = s3cfb_rgb_16.blue;
var->transp = s3cfb_rgb_16.transp;
s3cfb_fimd.bytes_per_pixel = 2;
break;


case 24:
var->red = s3cfb_rgb_24.red;
var->green = s3cfb_rgb_24.green;
var->blue = s3cfb_rgb_24.blue;
var->transp = s3cfb_rgb_24.transp;
s3cfb_fimd.bytes_per_pixel = 4;
break;


case 28:
var->red = s3cfb_rgb_28.red;
var->green = s3cfb_rgb_28.green;
var->blue = s3cfb_rgb_28.blue;
var->transp = s3cfb_rgb_28.transp;
s3cfb_fimd.bytes_per_pixel = 4;
break;


case 32:
var->red = s3cfb_rgb_32.red;
var->green = s3cfb_rgb_32.green;
var->blue = s3cfb_rgb_32.blue;
var->transp = s3cfb_rgb_32.transp;
s3cfb_fimd.bytes_per_pixel = 4;
break;
}


/* WIN0 cannot support alpha channel. */  窗口0不支持透明度模式
if( (fbi->win_id == 0) && (var->bits_per_pixel == 28) ){
var->transp.length = 0;
}

return 0;
}

当然,说是详细说这些函数,其实还不是特别详细,因为这涉及到太多的东西,但我们弄明白了这些函数的大致作用,至于具体参数的设置,就需要进一步分析了。