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;
}
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。