Imx6ULL LCD驱动分析

控制器特性

  • 支持MPU接口用于指令和数据传递
  • 支持DOTCKL接口(RGB mode)
  • 支持高速传输VSYNC mode
  • 支持 ITU-R BT.656 mode
    外部总线信号
    Imx6ULL LCD驱动分析_第1张图片

MPU接口时序

Imx6ULL LCD驱动分析_第2张图片

VSYNC接口时序

该接口时序协议和MPU接口保持一致,内部采用VSYNC 信号实现frame同步显示,比MPU多了一个VSYNC同步信号

DOTCLK接口时序 -RGB接口

Imx6ULL LCD驱动分析_第3张图片

DVI接口

在DVI模式下只用到了数据线LCD_DATA00~LCD_DATA07 和一个时钟线
Imx6ULL LCD驱动分析_第4张图片

Imx6ULL LCD驱动分析_第5张图片

Linux驱动之frame buff

framebuffer 概念介绍

1、framebuffer帧缓冲

帧缓冲(framebuffer)是Linux系统为显示设备提供的一个接口,它将显示缓冲区抽象,屏蔽图像硬件的底层差异,允许上层应用程序在图形模式下直接对显示缓冲区进行读写操作。用户不必关心物理显示缓冲区的具体位置及存放方式,这些都是由帧缓冲设备驱动本身来完成。
  framebuffer机制模仿显卡的功能,将显卡硬件结构抽象为一系列的数据结构,可以通过对framebuffer的读写直接对显存进行操作。用户可以将framebuffer看成是显卡的一个映像,将其映射到进程空间后,就可以直接读写操作,写操作会直接反映在屏幕上。
  framebuffer是一个字符设备,主设备号是29,对应于/dev/fb%d设备文件。通常,使用如下方式(数字代表次设备号)
  0 = /dev/fb0 第一个fb设备
  1 = /dev/fb1 第二个fb设备
  fb也是一种普通的内存设备,可以读写其内容。例如,屏幕抓屏:cp /dev/fb0 myfilefb 虽然可以向内存设备(/dev/mem)一样,对其read、write、seek以及mmap。但区别在于fb使用的不是整个内存区。而是显存部分。

2、fb与应用程序的互交
  对于应用程序而言,它和其它的设备并没有什么区别,用户可以把fb看成是一块内存,既可以向内存中写数据,也可以读数据。fb的显示缓冲区位于内核空间。应用程序可以把此空间映射到自己的用户空间,再进行操作。
  在应用程序中,操作/dev/fbn的一般步骤如下:
  (1)打开/dev/fbn设备文件。
  (2)用ioctl()操作取得当前显示屏幕的参数,如屏幕的分辨率、每个像素点的比特数。根据屏幕的参数可计算屏幕缓冲区的大小。
  (3)用mmap()函数,将屏幕缓冲区映射到用户空间。
  (4)映射后就可以直接读/写屏幕缓冲区,进行绘图和图片显示。

framebuffer数据结构分析

framebuffer涉及的数据结构如下:

(1)struct fb_info
   一个帧缓冲区对应一个struct fb_info结构,它包括了帧缓冲设备的属性和操作的完整集合,每个帧设备都有一个fb_info结构体。
  (2)struct fb_ops
    结构体用来实现对帧缓冲设备的操作,这些函数需要驱动开发人员编写,
  (3)struct fb_fix_screeninfo
    该结构体记录了用户不能修改的固定显示控制器参数。这些固定的参数如缓冲区的物理地址、缓冲区的长度等等。
  (4)struct fb_var_screeninfo
    结构体中存储了用户可以修改的显示器控制参数,例如屏幕分辨率、透明度等等。
  (5)struct fb_cmap
    结构体中记录了颜色板信息,即调色板信息。,用户空间可以通过ioctl()的FBIOGETCMAP和 FBIOPUTCMAP命令读取或设定颜色表
  (6)struct fb_bitfield
  结构体描述每一像素显示缓冲区的组织方式,包含位域偏移、位域长度和MSB 指示。
Imx6ULL LCD驱动分析_第6张图片

framebuffer核心层框架分析

framebuffer设备在Linux中是以平台设备形式存在的,fb设备驱动核心层为上层提供了系统调用,为底层驱动提供了接口,核心层的主文件及其功能如下。
  (1)drivers/video/fbmem.c。主要任务:1、创建graphics类、注册FB的字符设备驱动、提供register_framebuffer接口给具体framebuffer驱动编写着来注册fb设备的。本文件相对于fb来说,地位和作用和misc.c文件相对于杂散类设备来说一样的,结构和分析方法也是类似的。
  (2)drivers/video/fbsys.c。这个文件是处理fb在/sys目录下的一些属性文件的。
  (3)drivers/video/modedb.c。这个文件是管理显示模式(譬如VGA、720P等就是显示模式)的
  (4)drivers/video/fb_notify.c
Imx6ULL LCD驱动分析_第7张图片

	fbmem_init函数

(1)#ifdef MODULE
  (2)fb_proc_fops和fb在proc文件系统中的表现
  (3)register_chrdev注册fb设备
  (4)class_create创建graphics类
  (5)fbmem_exit的对应
  fb_fops
  (1)为应用层实现read/write/mmap/ioctl在驱动层的接口
  (2)registered_fb和num_registered_fb
  (3)struct fb_info  register_framebuffer函数

(1)fb驱动框架开放给驱动编写着的注册接口
  (2)fb_check_foreignness
  (3)remove_conflicting_framebuffers
  (4)device_create
  (5)fb_init_device

fb在sysfs中的接口
  (1)device_attrs
  (2)dev_set_drvdata和dev_get_drvdata

注册登记该fb设备
  (1)registered_fb[i] = fb_info;
  (2)结合fb_read等函数中对fb_info的使用
  (3)关键点:数据如何封装、数据由谁准备由谁消费、数据如何传递

imx6ull LCD驱动源码分析

static int imxfb_probe(struct platform_device *pdev)
{
     
	struct imxfb_info *fbi;
	struct lcd_device *lcd;
	struct fb_info *info;
	struct imx_fb_platform_data *pdata;
	struct resource *res;
	struct imx_fb_videomode *m;
	const struct of_device_id *of_id;
	int ret, i;
	int bytes_per_pixel;

	dev_info(&pdev->dev, "i.MX Framebuffer driver\n");

	:::::::://一些资源初始化
	//申请framebuff空间
	info = framebuffer_alloc(sizeof(struct imxfb_info), &pdev->dev);
	if (!info)
		return -ENOMEM;

	fbi = info->par;

	platform_set_drvdata(pdev, info);

	ret = imxfb_init_fbinfo(pdev);//主要填充部分屏参数变量 同时设置可操作函数
	if (ret < 0)
		goto failed_init;

	
	::::::::::::::::::::::::
	/* Calculate maximum bytes used per pixel. In most cases this should
	 * be the same as m->bpp/8 */
	 * 
//计算smem_len 的长度
	m = &fbi->mode[0];
	bytes_per_pixel = (m->bpp + 7) / 8;//像素所占字节
	for (i = 0; i < fbi->num_modes; i++, m++)
		info->fix.smem_len = max_t(size_t, info->fix.smem_len,
				m->mode.xres * m->mode.yres * bytes_per_pixel);//一帧总共有多少个字节

	res = request_mem_region(res->start, resource_size(res),//申请内存
				DRIVER_NAME);
	if (!res) {
     
		ret = -EBUSY;
		goto failed_req;
	}

	fbi->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
	if (IS_ERR(fbi->clk_ipg)) {
     
		ret = PTR_ERR(fbi->clk_ipg);
		goto failed_getclock;
	}

	fbi->clk_ahb = devm_clk_get(&pdev->dev, "ahb");
	if (IS_ERR(fbi->clk_ahb)) {
     
		ret = PTR_ERR(fbi->clk_ahb);
		goto failed_getclock;
	}

	fbi->clk_per = devm_clk_get(&pdev->dev, "per");
	if (IS_ERR(fbi->clk_per)) {
     
		ret = PTR_ERR(fbi->clk_per);
		goto failed_getclock;
	}

	fbi->regs = ioremap(res->start, resource_size(res));//内存映射
	if (fbi->regs == NULL) {
     
		dev_err(&pdev->dev, "Cannot map frame buffer registers\n");
		ret = -ENOMEM;
		goto failed_ioremap;
	}

	fbi->map_size = PAGE_ALIGN(info->fix.smem_len);//申请DMA的空间
	info->screen_base = dma_alloc_writecombine(&pdev->dev, fbi->map_size,
						   &fbi->map_dma, GFP_KERNEL);

	if (!info->screen_base) {
     
		dev_err(&pdev->dev, "Failed to allocate video RAM: %d\n", ret);
		ret = -ENOMEM;
		goto failed_map;
	}

	info->fix.smem_start = fbi->map_dma;

	if (pdata && pdata->init) {
     
		ret = pdata->init(fbi->pdev);
		if (ret)
			goto failed_platform_init;
	}


	INIT_LIST_HEAD(&info->modelist);
	for (i = 0; i < fbi->num_modes; i++)//设置video的模式
		fb_add_videomode(&fbi->mode[i].mode, &info->modelist);

	/*
	 * This makes sure that our colour bitfield
	 * descriptors are correctly initialised.
	 */
	imxfb_check_var(&info->var, info);

	ret = fb_alloc_cmap(&info->cmap, 1 << info->var.bits_per_pixel, 0);
	if (ret < 0)
		goto failed_cmap;

	imxfb_set_par(info);//设置LCD的具体参数
	ret = register_framebuffer(info);//注册frame buff
	if (ret < 0) {
     
		dev_err(&pdev->dev, "failed to register framebuffer\n");
		goto failed_register;
	}

	fbi->lcd_pwr = devm_regulator_get(&pdev->dev, "lcd");
	if (IS_ERR(fbi->lcd_pwr) && (PTR_ERR(fbi->lcd_pwr) == -EPROBE_DEFER)) {
     
		ret = -EPROBE_DEFER;
		goto failed_lcd;
	}

	lcd = devm_lcd_device_register(&pdev->dev, "imxfb-lcd", &pdev->dev, fbi,
				       &imxfb_lcd_ops);//lcd设备注册
	if (IS_ERR(lcd)) {
     
		ret = PTR_ERR(lcd);
		goto failed_lcd;
	}

	lcd->props.max_contrast = 0xff;

	imxfb_enable_controller(fbi);//使能控制器
	fbi->pdev = pdev;

	return 0;

failed_lcd:
	unregister_framebuffer(info);

failed_register:
	fb_dealloc_cmap(&info->cmap);
failed_cmap:
	if (pdata && pdata->exit)
		pdata->exit(fbi->pdev);
failed_platform_init:
	dma_free_writecombine(&pdev->dev, fbi->map_size, info->screen_base,
			      fbi->map_dma);
failed_map:
	iounmap(fbi->regs);
failed_ioremap:
failed_getclock:
	release_mem_region(res->start, resource_size(res));
failed_req:
failed_of_parse:
	kfree(info->pseudo_palette);
failed_init:
	framebuffer_release(info);
	return ret;
}

LCD设备管理功能

static struct lcd_ops imxfb_lcd_ops = {
     
	.check_fb	= imxfb_lcd_check_fb,//frame buff状态检测
	.get_contrast	= imxfb_lcd_get_contrast,//获取颜色偏差
	.set_contrast	= imxfb_lcd_set_contrast,//设置颜色偏差
	.get_power	= imxfb_lcd_get_power,//获取电源状态
	.set_power	= imxfb_lcd_set_power,//设置电源状态
};

具体画图功能实现函数集

static struct fb_ops imxfb_ops = {
     
	.owner		= THIS_MODULE,
	.fb_check_var	= imxfb_check_var,//检查变量设置是否越界
	.fb_set_par	= imxfb_set_par,//设置LCD参数变量
	.fb_setcolreg	= imxfb_setcolreg,//调试功能
	.fb_fillrect	= cfb_fillrect,//矩形填充
	.fb_copyarea	= cfb_copyarea,//颜色区域拷贝
	.fb_imageblit	= cfb_imageblit,//图像填充
	.fb_blank	= imxfb_blank,//LCD控制器使能和关闭
};

你可能感兴趣的:(嵌入式,接口,嵌入式,linux)