显示屏驱动

Posted 四季帆

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了显示屏驱动相关的知识,希望对你有一定的参考价值。

        继上篇继续分析。驱动第二层: mxc_ipuv3_fb.c

module_init(mxcfb_init);

int __init mxcfb_init(void)
{
	return platform_driver_register(&mxcfb_driver);
}

static struct platform_driver mxcfb_driver = {
	.driver = {
		.name = MXCFB_NAME,
		.of_match_table	= imx_mxcfb_dt_ids,
	},
	.probe = mxcfb_probe,
	.remove = mxcfb_remove,
	.suspend = mxcfb_suspend,
	.resume = mxcfb_resume,
};

static int mxcfb_probe(struct platform_device *pdev)
{
	struct ipuv3_fb_platform_data *plat_data;
	struct fb_info *fbi;
	struct mxcfb_info *mxcfbi;
	struct device *disp_dev;
	struct resource *res;
	int ret = 0;

	dev_dbg(&pdev->dev, "%s enter\\n", __func__);
	pdev->id = of_alias_get_id(pdev->dev.of_node, "mxcfb");   //获取fb 的id 号    
	plat_data = devm_kzalloc(&pdev->dev, sizeof(struct ipuv3_fb_platform_data), GFP_KERNEL);   //申请plat_data内存
	pdev->dev.platform_data = plat_data;			//将申请到的plat_data 内存地址赋值给pdev	
	ret = mxcfb_get_of_property(pdev, plat_data);	//获取设备树参数 --->2-1
	
	/* Initialize FB structures */
	fbi = mxcfb_init_fbinfo(&pdev->dev, &mxcfb_ops);    //初始化一个fb_info结构体并并填充ops --->2-2
	ret = mxcfb_option_setup(pdev, fbi);	//获取kernel cmdline 中的显示参数并覆盖设备树中设置的pdata->disp_dev --->2-3

	mxcfbi = (struct mxcfb_info *)fbi->par;
	mxcfbi->ipu_int_clk = plat_data->int_clk;
	mxcfbi->late_init = plat_data->late_init;
	mxcfbi->first_set_par = true;
	ret = mxcfb_dispdrv_init(pdev, fbi);	//初始化具体的显示屏控制器 --->2-4
	
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);	//获取framebuffer的资源
	if (res && res->start && res->end) {
		fbi->fix.smem_len = res->end - res->start + 1;  
		fbi->fix.smem_start = res->start; //将从设备树中获取到的frame buffer缓冲区的物理地址填充到fbi->fix.smem_start
		fbi->screen_base = ioremap(fbi->fix.smem_start, fbi->fix.smem_len);   //将frame buffer缓冲区的物理地址转化为虚拟地址(即成为可操控的显存)
		/* Do not clear the fb content drawn in bootloader. */
		if (!mxcfbi->late_init)
			memset(fbi->screen_base, 0, fbi->fix.smem_len);
	}

	mxcfbi->ipu = ipu_get_soc(mxcfbi->ipu_id);
	
	/* first user uses DP with alpha feature */
	if (!g_dp_in_use[mxcfbi->ipu_id]) {
		mxcfbi->ipu_ch_irq = IPU_IRQ_BG_SYNC_EOF;
		mxcfbi->ipu_ch_nf_irq = IPU_IRQ_BG_SYNC_NFACK;
		mxcfbi->ipu_alp_ch_irq = IPU_IRQ_BG_ALPHA_SYNC_EOF;
		mxcfbi->ipu_ch = MEM_BG_SYNC;
		
		ret = mxcfb_register(fbi);	//注册fb --->2-5
		ipu_disp_set_global_alpha(mxcfbi->ipu, mxcfbi->ipu_ch, true, 0x80);
		ipu_disp_set_color_key(mxcfbi->ipu, mxcfbi->ipu_ch, false, 0);
		res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
		ret = mxcfb_setup_overlay(pdev, fbi, res);

		g_dp_in_use[mxcfbi->ipu_id] = true;
		ret = device_create_file(mxcfbi->ovfbi->dev, &dev_attr_fsl_disp_property);	//创建属性文件		
		ret = device_create_file(mxcfbi->ovfbi->dev, &dev_attr_fsl_disp_dev_property);
	} 
	platform_set_drvdata(pdev, fbi);
	return 0;
 }

2-1代码分析

static int mxcfb_get_of_property(struct platform_device *pdev, struct ipuv3_fb_platform_data *plat_data)
{
	struct device_node *np = pdev->dev.of_node;
	const char *disp_dev;
	const char *mode_str;
	const char *pixfmt;
	int err;
	int len;
	u32 bpp, int_clk;
	u32 late_init;

	err = of_property_read_string(np, "disp_dev", &disp_dev);   //获取设备树中默认设置的各类参数
	err = of_property_read_string(np, "mode_str", &mode_str);
	err = of_property_read_string(np, "interface_pix_fmt", &pixfmt);
	err = of_property_read_u32(np, "default_bpp", &bpp);
	err = of_property_read_u32(np, "int_clk", &int_clk);
	err = of_property_read_u32(np, "late_init", &late_init);
	
	if (!strncmp(pixfmt, "RGB24", 5))
		plat_data->interface_pix_fmt = IPU_PIX_FMT_RGB24;
	else if (!strncmp(pixfmt, "LVDS666", 7))
		plat_data->interface_pix_fmt = IPU_PIX_FMT_LVDS666;
      ······
	else if (!strncmp(pixfmt, "YUYV16", 6))
		plat_data->interface_pix_fmt = IPU_PIX_FMT_YUYV;
	else {
		dev_err(&pdev->dev, "err interface_pix_fmt!\\n");
		return -ENOENT;
	}

	len = min(sizeof(plat_data->disp_dev) - 1, strlen(disp_dev));
	memcpy(plat_data->disp_dev, disp_dev, len);   //把前面从设备树中获取的各类参数设置到plat_data中
	plat_data->disp_dev[len] = '\\0';
	plat_data->mode_str = (char *)mode_str;
	plat_data->default_bpp = bpp;
	plat_data->int_clk = (bool)int_clk;
	plat_data->late_init = (bool)late_init;
	return err;
}

2-2代码分析

//传入的ops是mxcfb_ops结构体
static struct fb_ops mxcfb_ops = {
        .owner = THIS_MODULE,
        .fb_set_par = mxcfb_set_par,
        .fb_check_var = mxcfb_check_var,
        .fb_setcolreg = mxcfb_setcolreg,
        .fb_pan_display = mxcfb_pan_display,
        .fb_ioctl = mxcfb_ioctl,
        .fb_mmap = mxcfb_mmap,
        .fb_fillrect = cfb_fillrect,
        .fb_copyarea = cfb_copyarea,
        .fb_imageblit = cfb_imageblit,
        .fb_blank = mxcfb_blank,
};

static struct fb_info *mxcfb_init_fbinfo(struct device *dev, struct fb_ops *ops)
{
        struct fb_info *fbi;
        struct mxcfb_info *mxcfbi;
        
        fbi = framebuffer_alloc(sizeof(struct mxcfb_info), dev);
        mxcfbi = (struct mxcfb_info *)fbi->par;
        fbi->var.activate = FB_ACTIVATE_NOW;
        fbi->fbops = ops;    //填充ops
        return fbi;
}

2-3代码分析

static int mxcfb_option_setup(struct platform_device *pdev, struct fb_info *fbi)
{
	struct ipuv3_fb_platform_data *pdata = pdev->dev.platform_data;
	char *options, *opt, *fb_mode_str = NULL;
	char name[] = "mxcfb0";
	uint32_t fb_pix_fmt = 0;

	name[5] += pdev->id;
	if (fb_get_options(name, &options)) {      //获取kernel cmdline 中的显示参数
		dev_err(&pdev->dev, "Can't get fb option for %s!\\n", name);
		return -ENODEV;
	}

	while ((opt = strsep(&options, ",")) != NULL) {
		if (!*opt)
			continue;

		if (!strncmp(opt, "dev=", 4)) {
			memcpy(pdata->disp_dev, opt + 4, strlen(opt) - 4);
			pdata->disp_dev[strlen(opt) - 4] = '\\0';	//如果cmdline中指定了显示设备,则覆盖设备树中设置的pdata->disp_dev
		} else if (!strncmp(opt, "if=", 3)) {
			if (!strncmp(opt+3, "RGB24", 5))
				pdata->interface_pix_fmt = IPU_PIX_FMT_RGB24;
			else if (!strncmp(opt+3, "LVDS666", 7))
				pdata->interface_pix_fmt = IPU_PIX_FMT_LVDS666;
			else if (!strncmp(opt+3, "YUYV16", 6))
				pdata->interface_pix_fmt = IPU_PIX_FMT_YUYV;
		} else if (!strncmp(opt, "fbpix=", 6)) {
			if (!strncmp(opt+6, "RGB24", 5))
				fb_pix_fmt = IPU_PIX_FMT_RGB24;
			else if (!strncmp(opt+6, "RGB565", 6))
				fb_pix_fmt = IPU_PIX_FMT_RGB565;
			}
		} else if (!strncmp(opt, "int_clk", 7)) {
			pdata->int_clk = true;
			continue;
		} else if (!strncmp(opt, "bpp=", 4)) {
			fb_pix_fmt = bpp_to_pixfmt(pdata->default_bpp);
			if (fb_pix_fmt)
				pixfmt_to_var(fb_pix_fmt, &fbi->var);
		} else
			fb_mode_str = opt;
	}
	if (fb_mode_str)
		pdata->mode_str = fb_mode_str;

	return 0;
}

2-4代码分析

static int mxcfb_dispdrv_init(struct platform_device *pdev, struct fb_info *fbi)
{
	struct ipuv3_fb_platform_data *plat_data = pdev->dev.platform_data;
	struct mxcfb_info *mxcfbi = (struct mxcfb_info *)fbi->par;
	struct mxc_dispdrv_setting setting;
	char disp_dev[32], *default_dev = "lcd";
	int ret = 0;

	if (!strlen(plat_data->disp_dev)) {
		memcpy(disp_dev, default_dev, strlen(default_dev));
		disp_dev[strlen(default_dev)] = '\\0';
	} else {
		memcpy(disp_dev, plat_data->disp_dev, strlen(plat_data->disp_dev));	//由pdata->disp_dev构建 disp_dev 字符串
		disp_dev[strlen(plat_data->disp_dev)] = '\\0';
	}

	mxcfbi->dispdrv = mxc_dispdrv_gethandle(disp_dev, &setting);	//找到对应的drv,并调用drv->init --->
	dev_info(&pdev->dev, "registered mxc display driver %s\\n", disp_dev);
	return ret;
}

struct mxc_dispdrv_handle *mxc_dispdrv_gethandle(char *name, struct mxc_dispdrv_setting *setting)
{
	int ret, found = 0;
	struct mxc_dispdrv_entry *entry;

	mutex_lock(&dispdrv_lock);
	list_for_each_entry(entry, &dispdrv_list, list) {	//遍历dispdrv_list列表
		if (!strcmp(entry->drv->name, name) && (entry->drv->init)) {	//对比drv->name与name,找到对应的drv
			ret = entry->drv->init((struct mxc_dispdrv_handle *)	//调用drv->init
				entry, setting);
			if (ret >= 0) {
				entry->active = true;
				found = 1;
				break;
			}
		}
	}
	mutex_unlock(&dispdrv_lock);

	return found ? (struct mxc_dispdrv_handle *)entry:ERR_PTR(-ENODEV);
}

2-5代码分析

static int mxcfb_register(struct fb_info *fbi)
{
	struct mxcfb_info *mxcfbi = (struct mxcfb_info *)fbi->par;
	struct fb_videomode m;
	mxcfb_check_var(&fbi->var, fbi);
	mxcfb_set_fix(fbi);
	if (ipu_request_irq(mxcfbi->ipu, mxcfbi->ipu_ch_irq,
		mxcfb_irq_handler, IPU_IRQF_ONESHOT, MXCFB_NAME, fbi) != 0) {
		dev_err(fbi->device, "Error registering EOF irq handler.\\n");
		ret = -EBUSY;
		goto err0;
	}
	ipu_disable_irq(mxcfbi->ipu, mxcfbi->ipu_ch_irq);
    ······
	ret = register_framebuffer(fbi);   //调用第一层frame buffer框架层提供的接口注册fb_info结构体
	return ret;
}

以上是关于显示屏驱动的主要内容,如果未能解决你的问题,请参考以下文章

片段着色器中设置的颜色未显示 GLSL 1.30

Sphinx、reStructuredText 显示/隐藏代码片段

执行代码时有时不显示对话框片段

如何运用领域驱动设计 - 值对象

python selenium片段+网络驱动程序

如何在 Resharper IntelliSense 中显示所有 Visual Studio 代码片段?