Android GUI system

 

基于 atmel 的 sam9x5 系列的开发板 Android GUI 系统总结。

目前

  • 内核 linux-2.6.39
  • android 2.3.5

GUI 系统从下至上经过 :

Linux 内核驱动 —-> Gralloc HAL ——> FrameBufferNativeWindow ——->

首先看看内核的驱动主要是 LCD 显示驱动和 overlay 的基于 V4L 的 video 驱动。 9x5 的 LCD 控制器,支持 4 层显示, base/ovr1/HEO/HCC 。分别是 :

  • base 层,基本的显示层,我们一般的显示都是使用这一层,里面是唯一包含背光控制模块的一层。
  • ovr1 层,overlay 层,数据可以直接往这上面送,它的数据显示在 base 层之上,支持一些 rotation 和色彩变换
  • HEO 层,这一层的功能最多,支持 rotation 以及 scale 等,在驱动中使用 V4L 作成了 video 驱动。 HEO 和 OVR1 的显示位置可调节,可以设置寄存器支持谁显示在上面 HCC 层,这是一个硬件光标显示层,在 LCDC 显示在最上面。

目前的 2.6.39 驱动将前面的 3 个都做了出来, HCC 用的较少,所以还没有支持。

Linux 驱动

下面具体来分析一下这几层的 Linux 驱动程序。

首先在平台设备里面注册了我们需要的两个设备 baseovr1 的设备。 at91sam9x5_devices.c

static struct platform_device at91_lcdc_base_device = {
	.name		= "atmel_hlcdfb_base",
	.id		= 0,
	.dev		= {
				.dma_mask		= &lcdc_dmamask,
				.coherent_dma_mask	= DMA_BIT_MASK(32),
				.platform_data		= &lcdc_data,
	},
	.resource	= lcdc_base_resources,
	.num_resources	= ARRAY_SIZE(lcdc_base_resources),
};
static struct platform_device at91_lcdc_ovl_device = {
	.name		= "atmel_hlcdfb_ovl",
	.id		= 0,
	.dev		= {
				.dma_mask		= &lcdc_dmamask,
				.coherent_dma_mask	= DMA_BIT_MASK(32),
				.platform_data		= &lcdc_data,
	},
	.resource	= lcdc_ovl1_resources,
	.num_resources	= ARRAY_SIZE(lcdc_ovl1_resources),
};
void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
{
	platform_device_register(&at91_lcdc_base_device);
	platform_device_register(&at91_lcdc_ovl_device);
}

注册了两个设备 atmel_hlcdfb_base 和 atmel_hlcdfb_ovl

驱动程序 atmel_hlcdfb.c 将注册的两个设备放在 device tabel 中。他们公用一个设备驱动。

static const struct platform_device_id atmelfb_dev_table[] = {
	{ "atmel_hlcdfb_base", (kernel_ulong_t)&dev_data_base },
	{ "atmel_hlcdfb_ovl", (kernel_ulong_t)&dev_data_ovl },
}

驱动注册 :

static struct platform_driver atmel_hlcdfb_driver = {
	.remove		= __exit_p(atmel_hlcdfb_remove),
	.suspend	= atmel_hlcdfb_suspend,
	.resume		= atmel_hlcdfb_resume,

	.driver		= {
		.name	= "atmel_hlcdfb",
		.owner	= THIS_MODULE,
	},
	.id_table	= atmelfb_dev_table,
};

static int __init atmel_hlcdfb_init(void)
{
	return platform_driver_probe(&atmel_hlcdfb_driver, atmel_hlcdfb_probe);
}

Android HAL

在 android 中使用了 双缓冲的 机制,所以在内存的分配是

info->screen_base = dma_alloc_writecombine(info->device, info->fix.smem_len, (dma_addr_t *)&info->fix.smem_start, GFP_KERNEL); fix->smem_start 是 LCD 的真实物理地址,我们使用的是 info->screen_base ,操作的对象是一样的。 DMA 的自循环 : sinfo->dma_desc = dma_alloc_writecombine(info->device, sinfo->dev_data->dma_desc_size, &(sinfo->dma_desc_phys), GFP_KERNEL); 分配 dam_desc 的地址是在 dma_desc_phys 处。update dma 的时候 desc->next = sinfo->dma_desc_phys; 这样将会指向自己。DMA 访问的是物理地址。