TI Am335LCD驱动

drivers/video/da8xx-fb.c

platformdriver的名称是

#define DRIVER_NAME "da8xx_lcdc"

 

arch/arm/mach-omap2/devices.c中:

int __init am33xx_register_lcdc(struct da8xx_lcdc_platform_data *pdata)
{
	int id = 0;
	struct platform_device *pdev;
	struct omap_hwmod *oh;
	char *oh_name = "lcdc"; //驱动代码在arch/arm/mach-omap2/omap_hwmod_33xx_data.c
	char *dev_name = "da8xx_lcdc";

	oh = omap_hwmod_lookup(oh_name);
	if (!oh) {
		pr_err("Could not look up LCD%d hwmod\n", id);
		return -ENODEV;
	}

	pdev = omap_device_build(dev_name, id, oh, pdata,
			sizeof(struct da8xx_lcdc_platform_data), NULL, 0, 0);
	if (IS_ERR(pdev)) {
		WARN(1, "Can't build omap_device for %s:%s.\n",
			dev_name, oh->name);
		return PTR_ERR(pdev);
	}
	return 0;
}

这个函数是设置struct da8xx_lcdc_platform_data

board-am335xevm.c:

static const struct display_panel consys_disp_panel = {
	WVGA,
	32,
	32,
	COLOR_ACTIVE,
};
static struct lcd_ctrl_config consys_lcd_cfg = {
	&consys_disp_panel,
	.ac_bias		= 255,
	.ac_bias_intrpt		= 0,
	.dma_burst_sz		= 16,
	.bpp			= 32,     1个像素用多少位表示,这里其实是24位。在probe的代码使用了。
	.fdd			= 0x80,
	.tft_alt_mode		= 1,
	.stn_565_mode		= 0,
	.mono_8bit_mode		= 0,
	.invert_line_clock	= 0,
	.invert_frm_clock	= 0,
	.sync_edge		= 1,
	.sync_ctrl		= 1,
	.raster_order		= 0,
};
struct da8xx_lcdc_platform_data samsung_AMS369FG06_pdata = {
	.manu_name		= "SamSung",
	.controller_data	= &consys_lcd_cfg,
	.type			= "samsung_AMS369FG06",
};
static void lcdc_init(int evm_id, int profile)
{
	struct da8xx_lcdc_platform_data *lcdc_pdata;
	setup_pin_mux(lcdc_pin_mux);

	if (conf_disp_pll(300000000)) {
		pr_info("Failed configure display PLL, not attempting to"
				"register LCDC\n");
		return;
	}
	switch (evm_id) {
	case GEN_PURP_EVM:
	case GEN_PURP_DDR3_EVM:
		/*lcdc_pdata = &TFC_S9700RTWV35TR_01B_pdata;*/
		lcdc_pdata = &samsung_AMS369FG06_pdata;
		break;
	case EVM_SK:
		lcdc_pdata = &NHD_480272MF_ATXI_pdata;
		break;
	default:
		pr_err("LCDC not supported on this evm (%d)\n",evm_id);
		return;
	}

	lcdc_pdata->get_context_loss_count = omap_pm_get_dev_context_loss_count;

	if (am33xx_register_lcdc(lcdc_pdata))  //设置
		pr_info("Failed to register LCDC device\n");

	return;
}

回到开头来看Da8xx-fb.c:

static int __devinit fb_probe(struct platform_device *device)
{
	struct da8xx_lcdc_platform_data *fb_pdata =
						device->dev.platform_data;
	struct lcd_ctrl_config *lcd_cfg;
	struct da8xx_panel *lcdc_info;
	struct fb_info *da8xx_fb_info;
	struct clk *fb_clk = NULL;
	struct da8xx_fb_par *par;
	resource_size_t len;
	int ret, i;
	unsigned long ulcm;
代码略
    下面的代码申请LCD寄存器的虚拟地址,(这个resource是在哪定义的,还没找到)
	lcdc_regs = platform_get_resource(device, IORESOURCE_MEM, 0);
	if (!lcdc_regs) {
		dev_err(&device->dev,
			"Can not get memory resource for LCD controller\n");
		return -ENOENT;
	}

	len = resource_size(lcdc_regs);

	lcdc_regs = request_mem_region(lcdc_regs->start, len, lcdc_regs->name);
	if (!lcdc_regs)
		return -EBUSY;

	da8xx_fb_reg_base = (resource_size_t)ioremap(lcdc_regs->start, len);
代码略
    //上面定义了一些预定义的配置,见known_lcd_panels
	for (i = 0, lcdc_info = known_lcd_panels;
		i < ARRAY_SIZE(known_lcd_panels);
		i++, lcdc_info++) {
		if (strcmp(fb_pdata->type, lcdc_info->name) == 0)
			break;
	}

	if (i == ARRAY_SIZE(known_lcd_panels)) {
		dev_err(&device->dev, "GLCD: No valid panel found\n");
		ret = -ENODEV;
		goto err_pm_runtime_disable;
	} else
		dev_info(&device->dev, "GLCD: Found %s panel\n",
					fb_pdata->type);

	lcd_cfg = (struct lcd_ctrl_config *)fb_pdata->controller_data; //得到board-am335xevm.c中定义的lcd_ctrl_config

	da8xx_fb_info = framebuffer_alloc(sizeof(struct da8xx_fb_par),
					&device->dev);
	if (!da8xx_fb_info) {
		dev_dbg(&device->dev, "Memory allocation failed for fb_info\n");
		ret = -ENOMEM;
		goto err_pm_runtime_disable;
	}

下面初始化par变量。
	par = da8xx_fb_info->par;
	par->dev = &device->dev;
	par->lcdc_clk = fb_clk;
#ifdef CONFIG_CPU_FREQ
	par->lcd_fck_rate = clk_get_rate(fb_clk);
#endif
	par->pxl_clk = lcdc_info->pxl_clk;
	if (fb_pdata->panel_power_ctrl) {
		par->panel_power_ctrl = fb_pdata->panel_power_ctrl;
		par->panel_power_ctrl(1);
	}

调用lcd_init(),芯片级的初始化操作。
	if (lcd_init(par, lcd_cfg, lcdc_info) < 0) {
		dev_err(&device->dev, "lcd_init failed\n");
		ret = -EFAULT;
		goto err_release_fb;
	}
	/* allocate frame buffer */
	par->vram_size = lcdc_info->width * lcdc_info->height * lcd_cfg->bpp; //得到总共所需位数
	ulcm = lcm((lcdc_info->width * lcd_cfg->bpp)/8, PAGE_SIZE); //内存对齐
	par->vram_size = roundup(par->vram_size/8, ulcm); //1个字节8位,除8得到字节数。
	par->vram_size = par->vram_size * LCD_NUM_BUFFERS; //需求申请的内存的个数为LCD_NUM_BUFFERS

    申请DMA内存区域
	par->vram_virt = dma_alloc_coherent(NULL,
					    par->vram_size,
					    (resource_size_t *) &par->vram_phys,
					    GFP_KERNEL | GFP_DMA);
	if (!par->vram_virt) {
		dev_err(&device->dev,
			"GLCD: kmalloc for frame buffer failed\n");
		ret = -EINVAL;
		goto err_release_fb;
	}

	da8xx_fb_info->screen_base = (char __iomem *) par->vram_virt;
	da8xx_fb_fix.smem_start    = par->vram_phys;
	da8xx_fb_fix.smem_len      = par->vram_size;
	da8xx_fb_fix.line_length   = (lcdc_info->width * lcd_cfg->bpp) / 8;

       memcpy(par->vram_virt,kernel_logo,par->vram_size);//add by jiachenghui for kernel logo show
       
	par->dma_start = par->vram_phys;
	par->dma_end   = par->dma_start + lcdc_info->height *
		da8xx_fb_fix.line_length - 1;

	/* allocate palette buffer */
	par->v_palette_base = dma_alloc_coherent(NULL,
					       PALETTE_SIZE,
					       (resource_size_t *)
					       &par->p_palette_base,
					       GFP_KERNEL | GFP_DMA);
	if (!par->v_palette_base) {
		dev_err(&device->dev,
			"GLCD: kmalloc for palette buffer failed\n");
		ret = -EINVAL;
		goto err_release_fb_mem;
	}
	memset(par->v_palette_base, 0, PALETTE_SIZE);

	par->irq = platform_get_irq(device, 0);
	if (par->irq < 0) {
		ret = -ENOENT;
		goto err_release_pl_mem;
	}
代码略(设置结构da8xx_fb_info)
	dev_set_drvdata(&device->dev, da8xx_fb_info);  //platform_driver其它函数可以得到它,见resume和suspend函数。

	/* initialize the vsync wait queue */
	init_waitqueue_head(&par->vsync_wait);
	par->vsync_timeout = HZ / 5;
	par->which_dma_channel_done = -1;
	spin_lock_init(&par->lock_for_chan_update);

	/* Register the Frame Buffer  */
	if (register_framebuffer(da8xx_fb_info) < 0) {    //见(2)
		dev_err(&device->dev,
			"GLCD: Frame Buffer Registration Failed!\n");
		ret = -EINVAL;
		goto err_dealloc_cmap;
	}
  1. known_lcd_panels的定义说明:

static struct da8xx_panel known_lcd_panels[] = {
	/* Sharp LCD035Q3DG01 */
	[0] = {
		.name = "Sharp_LCD035Q3DG01",
		.width = 320,
		.height = 240,
		.hfp = 8,
		.hbp = 6,
		.hsw = 0,
		.vfp = 2,
		.vbp = 2,
		.vsw = 0,
		.pxl_clk = 4608000,
		.invert_pxl_clk = 1,
	},
代码略
	[10] = {
		 /* samsung AMS369FG06-0 */
		.name = "samsung_AMS369FG06",
		.width = 480,
		.height = 800,
		.hfp = 8,
		.hbp = 7,
		.hsw = 1,
		.vfp = 8,
		.vbp = 7,
		.vsw = 1,
		.pxl_clk = 19200000,
		.invert_pxl_clk = 0,
	},
};

struct da8xx_panel定义如下:

struct da8xx_panel {
	const char	name[25];	/* Full name _ */
	unsigned short	width;
	unsigned short	height;
	int		hfp;		/* Horizontal front porch */
	int		hbp;		/* Horizontal back porch */
	int		hsw;		/* Horizontal Sync Pulse Width */
	int		vfp;		/* Vertical front porch */
	int		vbp;		/* Vertical back porch */
	int		vsw;		/* Vertical Sync Pulse Width */
	unsigned int	pxl_clk;	/* Pixel clock */
	unsigned char	invert_pxl_clk;	/* Invert Pixel clock */
};

2. register_framebuffer()

int register_framebuffer(struct fb_info *fb_info)

它注册结构fb_info到framebuff系统,fb_info中有一个重要的成员是fb_ops结构。例如:

static struct fb_ops da8xx_fb_ops = {
	.owner = THIS_MODULE,
	.fb_check_var = fb_check_var,
	.fb_setcolreg = fb_setcolreg,
	.fb_pan_display = da8xx_pan_display,
	.fb_ioctl = fb_ioctl,
	.fb_fillrect = cfb_fillrect,
	.fb_copyarea = cfb_copyarea,
	.fb_imageblit = cfb_imageblit,
	.fb_blank = cfb_blank,
};

fb_ops的函数中都有一个参数fb_info。

 

你可能感兴趣的:([驱动开发])