S3C2440上LCD驱动(FrameBuffer)实例开发讲解(二)
ate = FB_ACTIVATE_NOW;
fbinfo->var.accel_flags = 0;
fbinfo->var.vmode = FB_VMODE_NONINTERLACED;
fbinfo->var.xres = display->xres;
fbinfo->var.yres = display->yres;
fbinfo->var.bits_per_pixel = display->bpp;
/*指定对底层硬件操作的函数指针, 因内容较多故其定义在第③步中再讲*/
fbinfo->fbops = &my2440fb_ops;
fbinfo->flags = FBINFO_FLAG_DEFAULT;
fbinfo->pseudo_palette = &fbvar->pseudo_pal;
fbinfo->flags = FBINFO_FLAG_DEFAULT;
fbinfo->pseudo_palette = &fbvar->pseudo_pal;
/*初始化色调色板(颜色表)为空*/
for(i = 0; i < 256; i++)
{
fbvar->palette_buffer[i] = PALETTE_BUFF_CLEAR;
}
for (i = 0; i < mach_info->num_displays; i++) /*fb缓存的长度*/
{
/*计算FrameBuffer缓存的最大大小,这里右移3位(即除以8)是因为色位模式BPP是以位为单位*/
unsigned long smem_len = (mach_info->displays[i].xres * mach_info->displays[i].yres * mach_info->displays[i].bpp) >> 3;
if(fbinfo->fix.smem_len < smem_len)
{
fbinfo->fix.smem_len = smem_len;
}
}
/*初始化LCD控制器之前要延迟一段时间*/
msleep(1);
/*初始化完fb_info后,开始对LCD各寄存器进行初始化,其定义在后面讲到*/
my2440fb_init_registers(fbinfo);
/*初始化完寄存器后,开始检查fb_info中的可变参数,其定义在后面讲到*/
my2440fb_check_var(fbinfo);
/*申请帧缓冲设备fb_info的显示缓冲区空间,其定义在后面讲到*/
ret = my2440fb_map_video_memory(fbinfo);
if (ret)
{
dev_err(&pdev->dev, "failed to allocate video RAM: %d\n", ret);
ret = -ENOMEM;
goto err_nofb;
}
/*最后,注册这个帧缓冲设备fb_info到系统中, register_framebuffer定义在fb.h中在fbmem.c中实现*/
ret = register_framebuffer(fbinfo);
if (ret < 0)
{
dev_err(&pdev->dev, "failed to register framebuffer device: %d\n", ret);
goto err_video_nomem;
}
/*对设备文件系统的支持(对设备文件系统的理解请参阅:嵌入式Linux之我行——设备文件系统剖析与使用)
创建frambuffer设备文件,device_create_file定义在linux/device.h中*/
ret = device_create_file(&pdev->dev, &dev_attr_debug);
if (ret)
{
dev_err(&pdev->dev, "failed to add debug attribute\n");
}
return 0;
/*以下是上面错误处理的跳转点*/
err_nomem:
release_resource(fbvar->lcd_mem);
kfree(fbvar->lcd_mem);
err_nomap:
iounmap(fbvar->lcd_base);
err_noclk:
clk_disable(fbvar->lcd_clock);
clk_put(fbvar->lcd_clock);
err_noirq:
free_irq(fbvar->lcd_irq_no, fbvar);
err_nofb:
platform_set_drvdata(pdev, NULL);
framebuffer_release(fbinfo);
err_video_nomem:
my2440fb_unmap_video_memory(fbinfo);
return ret;
}
/*LCD中断服务程序*/
static irqreturn_t lcd_fb_irq(int irq, void *dev_id)
{
struct my2440fb_var *fbvar = dev_id;
void __iomem *lcd_irq_base;
unsigned long lcdirq;
/*LCD中断挂起寄存器基地址*/
lcd_irq_base = fbvar->lcd_base + S3C2410_LCDINTBASE;
/*读取LCD中断挂起寄存器的值*/
lcdirq = readl(lcd_irq_base + S3C24XX_LCDINTPND);
/*判断是否为中断挂起状态*/
if(lcdirq & S3C2410_LCDINT_FRSYNC)
{
/*填充调色板*/
if (fbvar->palette_ready)
{
my2440fb_write_palette(fbvar);
}
/*设置帧已插入中断请求*/
writel(S3C2410_LCDINT_FRSYNC, lcd_irq_base + S3C24XX_LCDINTPND);
writel(S3C2410_LCDINT_FRSYNC, lcd_irq_base + S3C24XX_LCDSRCPND);
}
return IRQ_HANDLED;
}
/*填充调色板*/
static void my2440fb_write_palette(struct my2440fb_var *fbvar)
{
unsigned int i;
void __iomem *regs = fbvar->lcd_base;
fbvar->palette_ready = 0;
for (i = 0; i < 256; i++)
{
unsigned long ent = fbvar->palette_buffer[i];
if (ent == PALETTE_BUFF_CLEAR)
{
continue;
}
writel(ent, regs + S3C2410_TFTPAL(i));
if (readw(regs + S3C2410_TFTPAL(i)) == ent)
{
fbvar->palette_buffer[i] = PALETTE_BUFF_CLEAR;
}
else
{
fbvar->palette_ready
- 嵌入式Web服务器移植与测试(03-03)
- 基于S3C2440的嵌入式IPv6防火墙设计(09-02)
- 基于OpenWrt的移动机器人系统设计(01-17)
- 基于S3C2440处理器Linux平台的物流配送系统设计(02-05)
- 基于嵌入式的杯突试验机测控系统设计与实现(02-12)
- 基于ARM的多路同步的A/D和D/A设计(06-29)