打印
[牛人杂谈]

关于nuc970 lcd的分析

[复制链接]
925|5
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
gwsan|  楼主 | 2021-6-5 20:58 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
一.关于硬件设备节点的描述

内核平台代码路径linux-3.10.x\arch\arm\mach-nuc970下dev.c

内核设备节点如下

struct platform_device nuc970fb_device_lcd = {
.name             = "nuc970-lcd",
.id               = -1,
.num_resources    = ARRAY_SIZE(nuc970fb_lcd_resource),
.resource         = nuc970fb_lcd_resource,     
.dev              = {
.dma_mask               = &nuc970fb_device_lcd_dmamask,
.coherent_dma_mask      = -1,
.platform_data  = &nuc970fb_fb_info,
}
};


使用特权

评论回复
沙发
gwsan|  楼主 | 2021-6-5 20:59 | 只看该作者
一.关于硬件设备节点的描述

内核平台代码路径linux-3.10.x\arch\arm\mach-nuc970下dev.c

内核设备节点如下

struct platform_device nuc970fb_device_lcd = {
.name             = "nuc970-lcd",
.id               = -1,
.num_resources    = ARRAY_SIZE(nuc970fb_lcd_resource),
.resource         = nuc970fb_lcd_resource,     
.dev              = {
.dma_mask               = &nuc970fb_device_lcd_dmamask,
.coherent_dma_mask      = -1,
.platform_data  = &nuc970fb_fb_info,
}
};


使用特权

评论回复
板凳
gwsan|  楼主 | 2021-6-5 21:00 | 只看该作者
自定义的lcd描述硬件设备结构体

static struct nuc970fb_mach_info nuc970fb_fb_info = {
.displays  = &nuc970fb_lcd_info[0],
.num_displays  = ARRAY_SIZE(nuc970fb_lcd_info),
.default_display = 0,
     .gpio_blen          = NUC970_PG3,
     .gpio_lcs           = NUC970_PG2,
};


使用特权

评论回复
地板
gwsan|  楼主 | 2021-6-5 21:00 | 只看该作者
其中的nuc970fb_lcd_info添加了屏幕的详细信息

static struct nuc970fb_display nuc970fb_lcd_info[] = {
#ifdef CONFIG_A025DL02_320X240
/* AUO A035QN02V0 320x240 TFT Panel , 18bits*/
[0] = {
.type = LCM_DCCS_VA_SRC_RGB565,
.width  = 320,
.height  = 240,
.xres = 320,
.yres = 240,
.bpp = 16,
.pixclock  = 4000000,
.left_margin  = 10,
.right_margin   = 54,
.hsync_len  = 10,
.upper_margin  = 2,
.lower_margin  = 4,
.vsync_len  = 1,
.dccs = 0x0e00041a,
.devctl  = 0x060800c0,
.fbctrl  = 0x00a000a0,
.scale  = 0x04000400,
},
#endif


使用特权

评论回复
5
gwsan|  楼主 | 2021-6-5 21:01 | 只看该作者
二,driver部分的代码

static struct platform_driver nuc970fb_driver = {
.probe  = nuc970fb_probe,
.remove  = nuc970fb_remove,
.suspend  = nuc970fb_suspend,
.resume  = nuc970fb_resume,
.driver  = {
.name = "nuc970-lcd",
.owner  = THIS_MODULE,
},
};


使用特权

评论回复
6
gwsan|  楼主 | 2021-6-5 21:03 | 只看该作者
其中probe函数的实现




static int nuc970fb_probe(struct platform_device *pdev)
{
struct nuc970fb_info *fbi;
struct nuc970fb_display *display;
struct fb_info    *fbinfo;
struct nuc970fb_mach_info *mach_info;
struct resource *res;
int ret;
int irq;
int i;
int size;
struct pinctrl *p;
struct clk *clkmux, *clkuplldiv;

dev_dbg(&pdev->dev, "devinit\n");

mach_info = pdev->dev.platform_data;
if (mach_info == NULL) {
dev_err(&pdev->dev,
"no platform data for lcd, cannot attach\n");
return -EINVAL;
}


if (mach_info->default_display > mach_info->num_displays) {
dev_err(&pdev->dev,
"default display No. is %d but only %d displays \n",
mach_info->default_display, mach_info->num_displays);
return -EINVAL;
}




display = mach_info->displays + mach_info->default_display;


irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "no irq for device\n");
return -ENOENT;
}


fbinfo = framebuffer_alloc(sizeof(struct nuc970fb_info), &pdev->dev);
if (!fbinfo)
return -ENOMEM;


platform_set_drvdata(pdev, fbinfo);


fbi = fbinfo->par;
fbi->dev = &pdev->dev;


res = platform_get_resource(pdev, IORESOURCE_MEM, 0);


size = resource_size(res);
fbi->mem = request_mem_region(res->start, size, pdev->name);
if (fbi->mem == NULL) {
dev_err(&pdev->dev, "failed to alloc memory region\n");
ret = -ENOENT;
goto free_fb;
}


fbi->io = ioremap(res->start, size);
if (fbi->io == NULL) {
dev_err(&pdev->dev, "ioremap() of lcd registers failed\n");
ret = -ENXIO;
goto release_mem_region;
}


fbi->irq_base = fbi->io + REG_LCM_INT_CS;


/* Stop the LCD */
writel(0, fbi->io + REG_LCM_DCCS);


/* fill the fbinfo*/
strcpy(fbinfo->fix.id, driver_name);
fbinfo->fix.type = FB_TYPE_PACKED_PIXELS;
fbinfo->fix.type_aux = 0;
fbinfo->fix.xpanstep = 0;
fbinfo->fix.ypanstep = 0;
fbinfo->fix.ywrapstep = 0;
fbinfo->fix.accel = FB_ACCEL_NONE;
fbinfo->var.nonstd = 0;
fbinfo->var.activate = FB_ACTIVATE_NOW;
fbinfo->var.accel_flags = 0;
fbinfo->var.vmode = FB_VMODE_NONINTERLACED;
fbinfo->fbops  = &nuc970fb_ops;
fbinfo->flags  = FBINFO_FLAG_DEFAULT;
fbinfo->pseudo_palette = &fbi->pseudo_pal;


ret = request_irq(irq, nuc970fb_irqhandler, 0,
  pdev->name, fbinfo);
if (ret) {
dev_err(&pdev->dev, "cannot register irq handler %d -err %d\n",
irq, ret);
ret = -EBUSY;
goto release_regs;
}


clk_prepare(clk_get(NULL, "lcd_hclk"));
clk_enable(clk_get(NULL, "lcd_hclk"));
fbi->clk = clk_get(NULL, "lcd_eclk");

    if(display->pixclock > 12000000)
    {
        // change clock source to upll
        clkmux = clk_get(NULL, "lcd_eclk_mux");
        if (IS_ERR(clkmux)) {
            printk(KERN_ERR "nuc970-lcd:failed to get lcd clock mux control\n");
            ret = PTR_ERR(clkmux);
            return ret;
        }


        clkuplldiv = clk_get(NULL, "lcd_uplldiv");
        if (IS_ERR(clkuplldiv)) {
            printk(KERN_ERR "nuc970-lcd:failed to get lcd clock divider control\n");
            ret = PTR_ERR(clkuplldiv);
            return ret;
        }

        // select lcd clock from upll
        clk_set_parent(clkmux, clkuplldiv);
    }

    clk_set_rate(fbi->clk, display->pixclock);


clk_prepare(fbi->clk);
clk_enable(fbi->clk);
fbi->clk_rate = clk_get_rate(fbi->clk);

dev_dbg(&pdev->dev, "got and enabled clock\n");


/* calutate the video buffer size */
for (i = 0; i < mach_info->num_displays; i++) {
unsigned long smem_len = mach_info->displays[i].xres;
smem_len *= mach_info->displays[i].yres;
smem_len *= mach_info->displays[i].bpp;
smem_len >>= 3;
if (fbinfo->fix.smem_len < smem_len)
fbinfo->fix.smem_len = smem_len;
}


/* Initialize Video Memory */
ret = nuc970fb_map_video_memory(fbinfo);
if (ret) {
printk(KERN_ERR "Failed to allocate video RAM: %x\n", ret);
goto release_clock;
}


dev_dbg(&pdev->dev, "got video memory\n");


fbinfo->var.xres = display->xres;
fbinfo->var.yres = display->yres;
fbinfo->var.bits_per_pixel = display->bpp;


nuc970fb_init_registers(fbinfo);


nuc970fb_check_var(&fbinfo->var, fbinfo);


ret = nuc970fb_cpufreq_register(fbi);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to register cpufreq\n");
goto free_video_memory;
}


ret = register_framebuffer(fbinfo);
if (ret) {
printk(KERN_ERR "failed to register framebuffer device: %d\n",
ret);
goto free_cpufreq;
}

#if defined(CONFIG_FB_NUC970_16BIT_PIN)
p = devm_pinctrl_get_select(&pdev->dev, "lcd-16bit");
#elif defined(CONFIG_FB_NUC970_18BIT_PIN)
p = devm_pinctrl_get_select(&pdev->dev, "lcd-18bit");
#else
p = devm_pinctrl_get_select(&pdev->dev, "lcd-24bit");
#endif
    if(IS_ERR(p)) {
        dev_err(&pdev->dev, "unable to reserve pin\n");
        ret = PTR_ERR(p);
    }
printk(KERN_INFO "fb%d: %s frame buffer device\n",
fbinfo->node, fbinfo->fix.id);

#ifdef CONFIG_ILI9431_MPU80_240x320
    init_ili9341(fbinfo);
#endif


return 0;


free_cpufreq:
nuc970fb_cpufreq_deregister(fbi);
free_video_memory:
nuc970fb_unmap_video_memory(fbinfo);
release_clock:
clk_disable(fbi->clk);
clk_put(fbi->clk);
free_irq(irq, fbi);
release_regs:
iounmap(fbi->io);
release_mem_region:
release_mem_region(res->start, size);
free_fb:
framebuffer_release(fbinfo);
return ret;
}



使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

68

主题

3427

帖子

1

粉丝