s3c6410硬件DISPLAY CONTROLLER(显示控制器)的地址链接
linux中LCD设备驱动(1)——framebuffer(帧缓冲)的链接地址
linux中LCD设备驱动(2)——基于s3c6410平台的链接地址
上一篇在说LCD设备驱动对应的probe函数时,没有说完,这一篇接着继续说probe函数。
s3cfb_pre_init();上一次说到了这个函数,而且还讲到了一个结构体s3cfb_fimd_info_t,并说了它的大致作用。
s3cfb_set_backlight_power(1);看名字就只到它的大致作用,与背光灯有关,源码如下:
static void s3cfb_set_backlight_power(int to)
{
s3cfb_fimd.backlight_power = to;
if (s3cfb_fimd.set_backlight_power)
(s3cfb_fimd.set_backlight_power)(to); 函数指针
}
s3cfb_set_lcd_power(1);和上的类似,列出其源码:
static void s3cfb_set_lcd_power(int to)
{
s3cfb_fimd.lcd_power = to;
if (s3cfb_fimd.set_lcd_power)
(s3cfb_fimd.set_lcd_power)(to);也是函数指针
}
s3cfb_set_backlight_level(S3CFB_DEFAULT_BACKLIGHT_LEVEL);也和上面差不多,就不说了。
info->clk = clk_get(NULL, "lcd");得到LCD对应的时钟
if (!info->clk || IS_ERR(info->clk)) {
printk(KERN_INFO "failed to get lcd clock source\n");
ret = -ENOENT;
goto release_io;
}
clk_enable(info->clk); 使能时钟
printk("S3C_LCD clock got enabled :: %ld.%03ld Mhz\n", PRINT_MHZ(clk_get_rate(info->clk)));
s3cfb_fimd.vsync_info.count = 0;
init_waitqueue_head(&s3cfb_fimd.vsync_info.wait_queue); //初始化帧同步信号的等待队列头
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);获取LCD平台设备所使用的中断号
if (res == NULL) {
dev_err(&pdev->dev, "failed to get irq\n");
ret = -ENXIO;
goto release_clock;
}
ret = request_irq(res->start, s3cfb_irq, 0, "s3c-lcd", pdev); //申请中断,中断处理函数为s3cfb_irq
if (ret != 0) {
printk("Failed to install irq (%d)\n", ret);
goto release_clock;
}
msleep(5);
for (index = 0; index < S3CFB_NUM; index++) { 这一点不是很理解,不明白S3CFB_NUM的含义?查看了2410的代码,发现没有这个循环。我猜测与6410的多层窗口显示有关。我在s3c6410的硬件LCD显示控制器那篇博客中,有过这么一句话:“显示控制器支持5 层图像窗口。”所以我才做这样的猜测。如果你知道了话,请告诉我,谢谢!
填充fb_info中的可变参数结构的成员和不可变参数结构的成员,fb_info结构体中个成员的含义我在第一篇中说过了,你可以去查看。源码如下:
static void s3cfb_init_fbinfo(s3cfb_info_t *finfo, char *drv_name, int index)
{
int i = 0;
if (index == 0)
s3cfb_init_hw();
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;
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;
}
/* Initialize video memory */ 帧缓冲设备显示缓冲区的内存分配
ret = s3cfb_map_video_memory(&s3cfb_info[index]);
if (ret) {
printk("Failed to allocate video RAM: %d\n", ret);
ret = -ENOMEM;
goto release_irq;
}
ret = s3cfb_init_registers(&s3cfb_info[index]); 对LCD各寄存器进行初始化,列出部分源码:
int s3cfb_init_registers(s3cfb_info_t *fbi)
{
..........
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);
...........
}
ret = s3cfb_check_var(&s3cfb_info[index].fb.var, &s3cfb_info[index].fb);此函数检查fb的相关参数,如果传递的参数不合法,则进行修改。列出其函数开头的注释:
/*
* 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.
*
*/
if (index < 2){
if (fb_alloc_cmap(&s3cfb_info[index].fb.cmap, 256, 0) < 0)这个函数和调色板有关,同样列出其注释:
/**
* fb_alloc_cmap - allocate a colormap
* @cmap: frame buffer colormap structure
* @len: length of @cmap
* @transp: boolean, 1 if there is transparency, 0 otherwise
*
* Allocates memory for a colormap @cmap. @len is the
* number of entries in the palette.
*
* Returns negative errno on error, or zero on success.
*
*/
goto dealloc_fb;
} else {
if (fb_alloc_cmap(&s3cfb_info[index].fb.cmap, 16, 0) < 0)
goto dealloc_fb;
}
ret = register_framebuffer(&s3cfb_info[index].fb); 注册这个帧缓冲设备(FrameBuffer)fb_info到系统当中,函数源码如下:这个函数的主要作用其实就是把fb_info结构体加入到全局量struct fb_info *registered_fb[FB_MAX]数组中,还有进行一些其他的初始化。
/**
*register_framebuffer - registers a frame buffer device
*@fb_info: frame buffer info structure
*
*Registers a frame buffer device @fb_info.
*
*Returns negative errno on error, or zero for success.
*
*/
int
register_framebuffer(struct fb_info *fb_info)
{
int i;
struct fb_event event;
s
if (ret < 0) {
printk(KERN_ERR "Failed to register framebuffer device: %d\n", ret);
goto free_video_memory;
}
printk(KERN_INFO "fb%d: %s frame buffer device\n", s3cfb_info[index].fb.node, s3cfb_info[index].fb.fix.id);
}
/* create device files */下面这些代码是对设备文件系统的支持,创建fb设备文件。
ret = device_create_file(&(pdev->dev), &dev_attr_backlight_power);
if (ret < 0)
printk(KERN_WARNING "s3cfb: failed to add entries\n");
ret = device_create_file(&(pdev->dev), &dev_attr_backlight_level);
if (ret < 0)
printk(KERN_WARNING "s3cfb: failed to add entries\n");
ret = device_create_file(&(pdev->dev), &dev_attr_lcd_power);
if (ret < 0)
printk(KERN_WARNING "s3cfb: failed to add entries\n");
return 0;
下面这些是错误处理函数:
free_video_memory:
s3cfb_unmap_video_memory(&s3cfb_info[index]);
release_irq:
free_irq(res->start, &info);
release_clock:
clk_disable(info->clk);
clk_put(info->clk);
release_io:
iounmap(info->io);
release_mem:
release_resource(info->mem);
kfree(info->mem);
dealloc_fb:
framebuffer_release(fbinfo);
return ret;
}
probe函数最主要的工作,就是对fb设备进行一定的初始化,申请内存等等,然后注册fb_info到系统中。
2、对应的romeve函数就不说了,就是对应申请的资源的释放,和注销fb_info结构体。
linux中LCD设备驱动(4)——基于s3c6410平台的链接地址