天天看点

展讯平台android display驱动分析

本文以展讯tshak平台的display controller为硬件模型,来说明Android底层显示驱动的实现原理。该硬件模型较基础和简单,目前大多SOC平台的硬件设计都变得越来越复杂,实现功能也越来越全面,但基于此平台的设计更方便理解。

1 display控制器

下图的结构即是显示控制器的模块组成,它内部集成了lcd显示相关的控制器:lcdc和dispc,其中lcdc仅支持MCU接口类型(DBI),而dispc支持DBI和DPI接口类型。 图片最上面的实现是lcdc,直接通过DBI进行了输出。 图片中间较复杂的内容是dispc,图像数据流流向 ddr sdram ------> dispc ------> panel,dispc通过axi总线连接ddr controller并获取ddr sdram中的图像数据,经由dispc处理后通过dbi/dpi等interface将图像输出给屏幕。 图片最下面是寄存器配置相关,一般寄存器配置在SOC内部通过ahb总线。

展讯平台android display驱动分析

blending

展讯平台dispc支持两层图像显示: image 层/OSD 层,image 层支持的图像格式: YUV422/YUV420/YUV400/RGB888/RGB565/RGB666/RGB555/PACK data,OSD 层支持的图像格式: RGB888/RGB565/RGB666/RGB555。下图是dispc内部blending的功能示意。 video和camera的图像一般是YUV格式的,UI的图像是RGB的。

展讯平台android display驱动分析

dithering

支持RGB888->RGB 666, RGB888->RGB 565。

输出接口

1. DBI接口, 就是通常所讲的MCU模式。LCD panel内部一般需要一块sram,刷新操作由lcd panel完成。控制简单方便,无需时钟和同步信号。

展讯平台android display驱动分析
  1. DPI接口,就是RGB模式。LCD panel内部一般不需要sram,刷新操作由外部输入的vsync完成。数据线和控制线分离显示数据直接写屏,速度快。
    展讯平台android display驱动分析

dpi时序图如下面两幅图所示。

展讯平台android display驱动分析
展讯平台android display驱动分析
  1. mipi mode

    command mode: panel可以自刷新,不需要sync信号。.

    video mode:需要sync信号进行刷新。

    手机平台目前最常用的方案,内容较多,在此不详述,可参考专业文档。

为方便理解输出接口,下面附一张屏幕显示驱动芯片ili9486的结构图,它与dispc的输出接口相连。它支持MCU,SPI,RGB,MIPI各种接口。

展讯平台android display驱动分析

2 display驱动

首先show一下display驱动的结构图,由三个层次组成,分别为fb, dispc和panel。

展讯平台android display驱动分析
static int sprdfb_probe(struct platform_device *pdev)
{
	struct fb_info *fb = NULL;
	struct sprdfb_device *dev = NULL;
	int ret = 0;
	//fb中结构体fb_info的申请和分配
	fb = framebuffer_alloc(sizeof(struct sprdfb_device), &pdev->dev);

	dev = fb->par;
	dev->fb = fb;
#ifdef CONFIG_OF
	dev->of_dev = &(pdev->dev);
	dev->dev_id = of_alias_get_id(pdev->dev.of_node, "lcd");
#else
	dev->dev_id = pdev->id;
#endif
	if((SPRDFB_MAINLCD_ID != dev->dev_id) &&(SPRDFB_SUBLCD_ID != dev->dev_id)){
		printk(KERN_ERR "sprdfb: sprdfb_probe fail. (unsupported device id)\n");
		goto err0;
	}

	switch(SPRDFB_IN_DATA_TYPE){
	case SPRD_IN_DATA_TYPE_ABGR888:
		dev->bpp = 32;
		break;
	case SPRD_IN_DATA_TYPE_BGR565:
		dev->bpp = 16;
		break;
	default:
		dev->bpp = 32;
		break;
	}

	if(SPRDFB_MAINLCD_ID == dev->dev_id){
		dev->ctrl = &sprdfb_dispc_ctrl;  //sprd dispc控制器
#ifdef CONFIG_OF
		if(0 != of_address_to_resource(pdev->dev.of_node, 0, &r)){
			printk(KERN_ERR "sprdfb: sprdfb_probe fail. (can't get register base address)\n");
			goto err0;
		}
		//寄存器
		g_dispc_base_addr = (unsigned long)ioremap_nocache(r.start,
				resource_size(&r));
		if(!g_dispc_base_addr)
			BUG();
		printk("sprdfb: set g_dispc_base_addr = %ld\n", g_dispc_base_addr);
#endif
	}

	dev->frame_count = 0;
	dev->logo_buffer_addr_v = 0;
	dev->capability = sprdfb_config_capability();

	if(sprdfb_panel_get(dev)){
#if defined(CONFIG_FB_LCD_OLED_BACKLIGHT)
		if (dev->panel->ops->panel_dimming_init)
				dev->panel->ops->panel_dimming_init(dev->panel, &pdev->dev);
#endif
		dev->panel_ready = true;
		//一般显示相关驱动在uboot阶段已进行过初始化,所以此处可以直接使用
		dev->ctrl->logo_proc(dev);
	}else{
		dev->panel_ready = false;
	}

	dev->ctrl->early_init(dev); //sprd dispc控制器的early_init,其中有vsync中断的申请

	if(!dev->panel_ready){
		if (!sprdfb_panel_probe(dev)) {  //panel注册
			ret = -EIO;
			goto cleanup;
		}
	}

	ret = setup_fb_mem(dev, pdev);  //申请fb的memory,一般在dts中有reservemem
	if (ret) {
		goto cleanup;
	}


//配置fb_info成员参数,除了变量信息外,还会设置ops信息,其中最常用的就是mmap函数,将
//framebuffer的物理内存映射给usersapce使用
	setup_fb_info(dev);  
	/* register framebuffer device */
	ret = register_framebuffer(fb);     //fb设备注册
	if (ret) {
		printk(KERN_ERR "sprdfb: sprdfb_probe register framebuffer fail.\n");
		goto cleanup;
	}
	platform_set_drvdata(pdev, dev);
	sprdfb_create_sysfs(dev);
	dev->ctrl->init(dev);  //sprd dispc控制器的init

...

	return 0;
}

struct display_ctrl sprdfb_dispc_ctrl = {
	.name		= "dispc",
	.early_init		= sprdfb_dispc_early_init,
	.init		 	= sprdfb_dispc_init,
	.uninit		= sprdfb_dispc_uninit,
	.refresh		= sprdfb_dispc_refresh,
	.logo_proc		= sprdfb_dispc_logo_proc,
	.update_clk	= dispc_update_clk_intf,
	.is_refresh_done = sprdfb_is_refresh_done,
	...
};

           
展讯平台android display驱动分析

3 调试问题

帧率

dpi_clk的计算方法如下: dpi_clk=(witdh+hfp+hbp+hsync)* (height+vfp+vbp+vsync)*fps

例如需配置帧率的话需要根据配置的dpi_clock,对除width/height这类图像固有参数以外参数进行配置。

dpi_clk=64M,如需配置720p的显示帧率为60的话,可使用后面对应的可变参数(720+4+80+4)*(1280+18+17+5)*60= 64M

图像问题

memory dump & screencap ...

继续阅读