4-6q环视之显示,fb的注册


framebuffer分析之fb的注册
1.
board-mx6q_sabresd.c里定义了4个平台设备私有数据,最终分别代表fb0,fb1,fb2,fb3
static struct ipuv3_fb_platform_data sabresd_fb_data[] = {
	{ /*fb0*/
	.disp_dev = "ldb1",
	.interface_pix_fmt = IPU_PIX_FMT_RGB666,
	.mode_str = "LDB-XGA",
	.default_bpp = 16,
	.int_clk = false,
	.late_init = false,
	}, {
	.disp_dev = "ldb2",
	.interface_pix_fmt = IPU_PIX_FMT_RGB666,
	.mode_str = "LDB-XGA",
	.default_bpp = 16,
	.int_clk = false,
	}, {
	.disp_dev = "lcd3",
	.interface_pix_fmt = IPU_PIX_FMT_RGB565,
	.mode_str = "CLAA-WVGA",
	.default_bpp = 16,
	.int_clk = false,
	.late_init = false,
	}, {
	.disp_dev = "ldb4",
	.interface_pix_fmt = IPU_PIX_FMT_RGB666,
	.mode_str = "LDB-VGA",
	.default_bpp = 16,
	.int_clk = false,
	.late_init = false,
	},
};
但是uboot参数中的video域可以更新掉其中的某一个,也就是说video域也是构造fb的平台设备私有数据的一种方式。比如
video=mxcfb1:dev=adv739x,BT656-PAL,if=BT656,fbpix=RGB565
则fb1就是adv739x,替换掉了ldb2.
替换过程见mxcfb_option_setup函数。

2.
board-mx6q_sabresd.c的board_init函数中,执行4次imx6q_add_ipuv3fb,
		for (i = 0; i < 4 && i < ARRAY_SIZE(sabresd_fb_data); i++)
			imx6q_add_ipuv3fb(i, &sabresd_fb_data[i]);
imx6q_add_ipuv3fb函数最终调用platform-imx_ipuv3.c里的imx_add_platform_device_dmamask("mxc_sdc_fb", id,NULL, 0, pdata, sizeof(*pdata),DMA_BIT_MASK(32));
可见是注册了4次平台设备。每次注册平台设备都会触发平台驱动的probe函数,往下看。

3.
平台驱动位于mxc_ipuv3_fb.c,在mxcfb_probe函数中创建fbi结构体
static int mxcfb_probe(struct platform_device *pdev)
{
	struct ipuv3_fb_platform_data *plat_data = pdev->dev.platform_data;
	struct fb_info *fbi;
	struct mxcfb_info *mxcfbi;
	struct resource *res;
	int ret = 0;

	/* Initialize FB structures */
	fbi = mxcfb_init_fbinfo(&pdev->dev, &mxcfb_ops);//重要
	if (!fbi) {
		ret = -ENOMEM;
		goto init_fbinfo_failed;
	}

	ret = mxcfb_option_setup(pdev, fbi);
	if (ret)
		goto get_fb_option_failed;

	mxcfbi = (struct mxcfb_info *)fbi->par;
	mxcfbi->ipu_int_clk = plat_data->int_clk;
	mxcfbi->late_init = plat_data->late_init;
	mxcfbi->fb_pix_fmt = plat_data->fb_pix_fmt;
	mxcfbi->first_set_par = true;
	ret = mxcfb_dispdrv_init(pdev, fbi);//重要
	if (ret < 0)
		goto init_dispdrv_failed;

	ret = ipu_test_set_usage(mxcfbi->ipu_id, mxcfbi->ipu_di);//重要
	if (ret < 0) {
		dev_err(&pdev->dev, "ipu%d-di%d already in use\n",
				mxcfbi->ipu_id, mxcfbi->ipu_di);
		goto ipu_in_busy;
	}

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (res && res->start && res->end) {
		fbi->fix.smem_len = res->end - res->start + 1;
		fbi->fix.smem_start = res->start;
		fbi->screen_base = ioremap(fbi->fix.smem_start, fbi->fix.smem_len);
		/* 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);
	if (IS_ERR(mxcfbi->ipu)) {
		ret = -ENODEV;
		goto get_ipu_failed;
	}

	/* 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;
		/* Unblank the primary fb only by default */
		if (pdev->id == 0)
			mxcfbi->cur_blank = mxcfbi->next_blank = FB_BLANK_UNBLANK;
		else
			mxcfbi->cur_blank = mxcfbi->next_blank = FB_BLANK_POWERDOWN;

		ret = mxcfb_register(fbi);//重要
		if (ret < 0)
			goto mxcfb_register_failed;

		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);

		if (ret < 0) {
			mxcfb_unregister(fbi);
			goto mxcfb_setupoverlay_failed;
		}

		g_dp_in_use[mxcfbi->ipu_id] = true;

		ret = device_create_file(mxcfbi->ovfbi->dev,
					 &dev_attr_fsl_disp_property);
		if (ret)
			dev_err(mxcfbi->ovfbi->dev, "Error %d on creating "
						    "file for disp property\n",
						    ret);

		ret = device_create_file(mxcfbi->ovfbi->dev,
					 &dev_attr_fsl_disp_dev_property);
		if (ret)
			dev_err(mxcfbi->ovfbi->dev, "Error %d on creating "
						    "file for disp device "
						    "propety\n", ret);
	} else {
		mxcfbi->ipu_ch_irq = IPU_IRQ_DC_SYNC_EOF;
		mxcfbi->ipu_ch_nf_irq = IPU_IRQ_DC_SYNC_NFACK;
		mxcfbi->ipu_alp_ch_irq = -1;
		mxcfbi->ipu_ch = MEM_DC_SYNC;
		mxcfbi->cur_blank = mxcfbi->next_blank = FB_BLANK_POWERDOWN;

		ret = mxcfb_register(fbi);
		if (ret < 0)
			goto mxcfb_register_failed;
	}

	platform_set_drvdata(pdev, fbi);

	ret = device_create_file(fbi->dev, &dev_attr_fsl_disp_property);
	if (ret)
		dev_err(&pdev->dev, "Error %d on creating file for disp "
				    "property\n", ret);

	ret = device_create_file(fbi->dev, &dev_attr_fsl_disp_dev_property);
	if (ret)
		dev_err(&pdev->dev, "Error %d on creating file for disp "
				    " device propety\n", ret);

#ifdef CONFIG_LOGO
	fb_prepare_logo(fbi, 0);//重要
	fb_show_logo(fbi, 0);
#endif

	return 0;

mxcfb_setupoverlay_failed:
mxcfb_register_failed:
get_ipu_failed:
	ipu_clear_usage(mxcfbi->ipu_id, mxcfbi->ipu_di);
ipu_in_busy:
init_dispdrv_failed:
	fb_dealloc_cmap(&fbi->cmap);
	framebuffer_release(fbi);
get_fb_option_failed:
init_fbinfo_failed:
	return ret;
}

一一分析上面标记重要的几个函数
一、mxcfb_init_fbinfo,
内部调用 framebuffer_alloc();来分配fbi和fbi的私有指针即mxcfbi的内存
二、mxcfb_option_setup
用来解析uboot中的video参数比如“video=mxcfb1:dev=adv739x,BT656-PAL,if=BT656,fbpix=RGB565  video=mxcfb2:dev=hdmi,1280x720M@60,if=RGB24,fbpix=RGB565”
第一次调用mxcfb_option_setup会查找名字是mxcfb0的uboot参数,第二次查找名字是mxcfb1的uboot参数,第三次查找名字是mxcfb2的uboot参数,,这个函数随着probe函数共计调用了4次。所以本例中,最终fb0是ldb1,fb1是adv739x,fb2是hdmi,fb3是ldb4.

三、mxcfb_dispdrv_init
uboot的video域更新了fb1和fb2的平台私有数据。fb0和fb3的没有更新,还是使用board-mx6q_sabresd.c的sabresd_fb_data数组里面的。
而私有数据的结构体是ipuv3_fb_platform_data
struct ipuv3_fb_platform_data {
	char				disp_dev[32];
	u32 				fb_pix_fmt;
	u32				interface_pix_fmt;
	char				*mode_str;
	int				default_bpp;
	bool				int_clk;
	bool                            late_init;
};
其中,disp_dev是连接显示设备驱动和fb驱动的标示:在mxcfb_dispdrv_init函数中调用mxc_dispdrv_gethandle函数来根据disp_dev获取到对应的显示设备,并得到其驱动指针mxc_dispdrv_driver。同时调用mxc_dispdrv_driver的init函数,来初始化显示设备。
mxc_dispdrv_driver几乎是显示设备的全部家当(就像fbi是fb的全部家当一样),所有的东东都在这个结构体里面,下篇会讲。


四、mxcfb_register

此函数会调用register_framebuffer来注册fb,生成fbn。第一次调用register_framebuffer会生成fb0,第二次是fb1,第三次是fb2,,,顺序加1的。
register_framebuffer定义在fbmem.c中
register_framebuffer(struct fb_info *fb_info)
{
	int ret;

	mutex_lock(&registration_lock);
	ret = do_register_framebuffer(fb_info);
	mutex_unlock(&registration_lock);

	return ret;
}


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值