s5p4418显示驱动
发布日期:2021-09-16 16:46:42 浏览次数:3 分类:技术文章

本文共 13216 字,大约阅读时间需要 44 分钟。

arch/arm/plat-s5p4418/drone2/include/Cfg_main.h

有关显示的定义:

/*------------------------------------------------------------------------------* Display (DPC and MLC)*//* Primary */#define CFG_DISP_PRI_SCREEN_LAYER 0#define CFG_DISP_PRI_SCREEN_RGB_FORMAT MLC_RGBFMT_A8R8G8B8#define CFG_DISP_PRI_SCREEN_PIXEL_BYTE 4#define CFG_DISP_PRI_SCREEN_COLOR_KEY 0x090909#define CFG_DISP_PRI_VIDEO_PRIORITY 2 // 0, 1, 2, 3#define CFG_DISP_PRI_BACK_GROUND_COLOR 0x000000#define CFG_DISP_PRI_MLC_INTERLACE CFALSE#define CFG_DISP_PRI_LCD_WIDTH_MM 154#define CFG_DISP_PRI_LCD_HEIGHT_MM 85#define CFG_DISP_PRI_RESOL_WIDTH 480 // X Resolution#define CFG_DISP_PRI_RESOL_HEIGHT 800 // Y Resolution红色的部分即对应驱动代码中的struct disp_vsync_info结构。这此数据在dev-display.c中设置。#define CFG_DISP_PRI_HSYNC_SYNC_WIDTH 1#define CFG_DISP_PRI_HSYNC_BACK_PORCH 7#define CFG_DISP_PRI_HSYNC_FRONT_PORCH 8#define CFG_DISP_PRI_HSYNC_ACTIVE_HIGH CTRUE#define CFG_DISP_PRI_VSYNC_SYNC_WIDTH 1#define CFG_DISP_PRI_VSYNC_BACK_PORCH 7#define CFG_DISP_PRI_VSYNC_FRONT_PORCH 8#define CFG_DISP_PRI_VSYNC_ACTIVE_HIGH CTRUE#define CFG_DISP_PRI_CLKGEN0_SOURCE DPC_VCLK_SRC_PLL2#define CFG_DISP_PRI_CLKGEN0_DIV 40// even divide#define CFG_DISP_PRI_CLKGEN0_DELAY 0#define CFG_DISP_PRI_CLKGEN0_INVERT 0#define CFG_DISP_PRI_CLKGEN1_SOURCE DPC_VCLK_SRC_VCLK2#define CFG_DISP_PRI_CLKGEN1_DIV 2#define CFG_DISP_PRI_CLKGEN1_DELAY 0#define CFG_DISP_PRI_CLKGEN1_INVERT 0#define CFG_DISP_PRI_CLKSEL1_SELECT 0#define CFG_DISP_PRI_PADCLKSEL DPC_PADCLKSEL_VCLK /* VCLK=CLKGEN1, VCLK12=CLKGEN0 */#define CFG_DISP_PRI_PIXEL_CLOCK 800000000/CFG_DISP_PRI_CLKGEN0_DIV#define CFG_DISP_PRI_OUT_SWAPRB CFALSE#define CFG_DISP_PRI_OUT_FORMAT DPC_FORMAT_RGB888#define CFG_DISP_PRI_OUT_YCORDER DPC_YCORDER_CbYCrY#define CFG_DISP_PRI_OUT_INTERLACE CFALSE#define CFG_DISP_PRI_OUT_INVERT_FIELD CFALSE#define CFG_DISP_LCD_MPY_TYPE 0

这个表和LCD时序图有关:

VCLK表示LCD时钟频率。

HSYNC表示行同步,每个时钟周期表示扫描1行。

VSYNC表示帧同步,每个时钟周期表示扫描完1帧。

LINEVAL表示LCD垂直宽度。

HOZVAL表示LCD水平宽度。

LCD帧扫描流程:当VSYNC(脉冲宽度为VSPW+1)上升沿到来后经历VBPD+1个时钟周期后开始行扫描,VDEN表示行有效,经历LINEVAL+1个行信号后行扫描结束,再经历VFPD+1时钟后进行下一个帧信号。

行扫描流程:当HSYNC(脉冲宽度为HSPW+1)上升沿后HBPD+1周期后开始扫描每个点,经历HOZVAL+1个点后行扫描结束,再经历HFPD+1个周期后开始下一行。

 

 

arch/arm/plat-s5p4418/dron2/device.c

/*------------------------------------------------------------------------------* DISPLAY (LVDS) / FB*/#if defined (CONFIG_FB_NXP)#if defined (CONFIG_FB0_NXP)static struct nxp_fb_plat_data fb0_plat_data = {.module = CONFIG_FB0_NXP_DISPOUT,.layer = CFG_DISP_PRI_SCREEN_LAYER,.format = CFG_DISP_PRI_SCREEN_RGB_FORMAT,.bgcolor = CFG_DISP_PRI_BACK_GROUND_COLOR,.bitperpixel = CFG_DISP_PRI_SCREEN_PIXEL_BYTE * 8,.x_resol = CFG_DISP_PRI_RESOL_WIDTH,.y_resol = CFG_DISP_PRI_RESOL_HEIGHT,#ifdef CONFIG_ANDROID.buffers = 3,.skip_pan_vsync = 1,#else.buffers = 2,#endif.lcd_with_mm = CFG_DISP_PRI_LCD_WIDTH_MM, /* 152.4 */.lcd_height_mm = CFG_DISP_PRI_LCD_HEIGHT_MM, /* 91.44 */};static struct platform_device fb0_device = {.name = DEV_NAME_FB, //“nxp-fb”.id = 0, /* FB device node num */.dev = {.coherent_dma_mask = 0xffffffffUL, /* for DMA allocate */.platform_data = &fb0_plat_data},};#endifstatic struct platform_device *fb_devices[] = {#if defined (CONFIG_FB0_NXP)&fb0_device,#endif};#endif /* CONFIG_FB_NXP */

arch/arm/plat-s5p4418/dron2/dev-display.c

这个文件是为display_lcd.c(见下面,这是platform_driver)服务的,这里定义platform_data。

/*------------------------------------------------------------------------------* LCD platform device*/#if defined (CONFIG_NXP_DISPLAY_LCD)static struct disp_vsync_info __lcd_vsync = {/* default parameters refer to cfg_main.h */#if defined(CFG_DISP_PRI_RESOL_WIDTH) && defined(CFG_DISP_PRI_RESOL_HEIGHT).h_active_len = CFG_DISP_PRI_RESOL_WIDTH,.h_sync_width = CFG_DISP_PRI_HSYNC_SYNC_WIDTH,.h_back_porch = CFG_DISP_PRI_HSYNC_BACK_PORCH,.h_front_porch = CFG_DISP_PRI_HSYNC_FRONT_PORCH,.h_sync_invert = CFG_DISP_PRI_HSYNC_ACTIVE_HIGH,.v_active_len = CFG_DISP_PRI_RESOL_HEIGHT,.v_sync_width = CFG_DISP_PRI_VSYNC_SYNC_WIDTH,.v_back_porch = CFG_DISP_PRI_VSYNC_BACK_PORCH,.v_front_porch = CFG_DISP_PRI_VSYNC_FRONT_PORCH,.v_sync_invert = CFG_DISP_PRI_VSYNC_ACTIVE_HIGH,.pixel_clock_hz = CFG_DISP_PRI_PIXEL_CLOCK,.clk_src_lv0 = CFG_DISP_PRI_CLKGEN0_SOURCE,.clk_div_lv0 = CFG_DISP_PRI_CLKGEN0_DIV,.clk_src_lv1 = CFG_DISP_PRI_CLKGEN1_SOURCE,.clk_div_lv1 = CFG_DISP_PRI_CLKGEN1_DIV,#endif};static struct disp_lcd_param __lcd_devpar; //注意,没有做初始化,但在下面的函数__disp_lcd_dev_data赋了值。static struct nxp_lcd_plat_data lcd_data = {.display_in = DISPLAY_INPUT(CONFIG_NXP_DISPLAY_LCD_IN),.display_dev = DISP_DEVICE_LCD,.vsync = &__lcd_vsync,.dev_param = (union disp_dev_param*)&__lcd_devpar,};//此结构没有被使用。static struct platform_device lcd_device = {.name = DEV_NAME_LCD, // "nxp-lcd" //arch/arm/plat-s5p4418/soc/display_lcd.c是此名称的platform_driver驱动.id = -1,.dev = {.platform_data = &lcd_data},};//此函数的作用是将dev_par, sgpar的参数都复制到本地lcd_data实体,并将lcd_data.vsync复制到输出参数*vsync。lcd_data实体是arch/arm/mach-s5p4418/display_lcd.c中的platform_driver中的platform_datastatic void __disp_lcd_dev_data(struct disp_vsync_info *vsync,void *dev_par, struct disp_syncgen_par *sgpar){struct nxp_lcd_plat_data *plcd = &lcd_data; //lcd_data是本地数据。struct disp_lcd_param *dst = (struct disp_lcd_param *)plcd->dev_param;struct disp_lcd_param *src = dev_par;if (src) {SET_PARAM(src, dst, lcd_format);SET_PARAM(src, dst, lcd_mpu_type);SET_PARAM(src, dst, invert_field);SET_PARAM(src, dst, swap_RB);SET_PARAM(src, dst, yc_order);SET_PARAM(src, dst, lcd_init);SET_PARAM(src, dst, lcd_exit);}if (sgpar)plcd->sync_gen = sgpar;SET_VSYNC_INFO(vsync, plcd->vsync);}#else#define __disp_lcd_dev_data(s, p, g)#endif /* LCD */

arch/arm/mach-s5p4418/soc/display_lcd.c

它是一个platform_driver,注册的platform_driver是

#define DEV_NAME_LCD "nxp-lcd"

 

它为display.c(见下面)服务,注册disp_process_ops结构。

static struct disp_process_ops lcd_ops = {.set_vsync = lcd_set_vsync,.get_vsync = lcd_get_vsync,.enable = lcd_enable,.stat_enable= lcd_stat_enable,.suspend = lcd_suspend,.resume = lcd_resume,};static int lcd_probe(struct platform_device *pdev){struct nxp_lcd_plat_data *plat = pdev->dev.platform_data;struct disp_lcd_param *plcd;struct disp_vsync_info *psync;struct disp_syncgen_par *sgpar;int device = DISP_DEVICE_LCD;int input;RET_ASSERT_VAL(plat, -EINVAL);RET_ASSERT_VAL(plat->display_in == DISP_DEVICE_SYNCGEN0 ||plat->display_in == DISP_DEVICE_SYNCGEN1 ||plat->display_dev == DISP_DEVICE_LCD ||plat->display_in == DISP_DEVICE_RESCONV, -EINVAL);RET_ASSERT_VAL(plat->vsync, -EINVAL);plcd = kzalloc(sizeof(*plcd), GFP_KERNEL);RET_ASSERT_VAL(plcd, -EINVAL);if (plat->dev_param)memcpy(plcd, plat->dev_param, sizeof(*plcd));sgpar = plat->sync_gen;psync = plat->vsync;input = plat->display_in;//在dev-display.c中设置lcd_data->display_in= DISP_DEVICE_SYNCGEN0nxp_soc_disp_register_proc_ops(device, &lcd_ops); //此注册函数在同目录下的display.c中nxp_soc_disp_device_connect_to(device, input, psync);nxp_soc_disp_device_set_dev_param(device, plcd);if (sgpar &&(input == DISP_DEVICE_SYNCGEN0 ||input == DISP_DEVICE_SYNCGEN1))nxp_soc_disp_device_set_sync_param(input, sgpar);printk("LCD : [%d]=%s connect to [%d]=%s\n",device, dev_to_str(device), input, dev_to_str(input));return 0;}

第一句:struct nxp_lcd_plat_data *plat = pdev->dev.platform_data;

对应dev-display.c中:

static struct platform_device lcd_device = { 但代码中没有找到驱动注册此结构的代码,为何??.name = DEV_NAME_LCD,.id = -1,.dev = {.platform_data = &lcd_data},};

arch/arm/mach-s5p4418/soc/display.c

此文件内部有一组显示结构,它将所有显示有关的设备(包括LCD)定义了一个内部数据结构数组:

static struct disp_process_dev device_dev[] = {[0] = { .dev_id = DISP_DEVICE_RESCONV , .name = "RESCONV" , .list = LIST_INIT(0), .lock = LOCK_INIT(0)},[1] = { .dev_id = DISP_DEVICE_LCD , .name = "LCD" , .list = LIST_INIT(1), .lock = LOCK_INIT(1)},[2] = { .dev_id = DISP_DEVICE_HDMI , .name = "HDMI" , .list = LIST_INIT(2), .lock = LOCK_INIT(2)},[3] = { .dev_id = DISP_DEVICE_MIPI , .name = "MiPi" , .list = LIST_INIT(3), .lock = LOCK_INIT(3)},[4] = { .dev_id = DISP_DEVICE_LVDS , .name = "LVDS" , .list = LIST_INIT(4), .lock = LOCK_INIT(4)},[5] = { .dev_id = DISP_DEVICE_SYNCGEN0, .name = "SYNCGEN0", .list = LIST_INIT(5), .lock = LOCK_INIT(5)},[6] = { .dev_id = DISP_DEVICE_SYNCGEN1, .name = "SYNCGEN1", .list = LIST_INIT(6), .lock = LOCK_INIT(6)},};#define DEVICE_SIZE ARRAY_SIZE(device_dev)static struct kobject *kobj_syncgen = NULL;static inline void *get_display_ptr(enum disp_dev_type device) //根据参数得到指定的结构指针{return (&device_dev[device]);}const char * dev_to_str(enum disp_dev_type device) //打印出名称{struct disp_process_dev *pdev = get_display_ptr(device);return pdev->name;}

每一个显示设备都是disp_process_dev结构:

/* display device instance (syncgen, lvds, lcd,..) */struct disp_process_dev {const char *name;int dev_id;int dev_in;int dev_out;unsigned int save_addr;unsigned int base_addr;struct list_head list;unsigned int status;spinlock_t lock;struct disp_vsync_info vsync;struct disp_syncgen_par sync_gen;struct disp_process_ops *disp_ops; //即是上面display_lcd.c中定义的disp_process_opsvoid * dev_param;void * dev_info;void * priv;};

 

分析display_lcd.c中使用的第一个函数nxp_soc_disp_register_proc_ops:

此函数将ops赋给内部数据device_dev[1]->disp_ops。void nxp_soc_disp_register_proc_ops(enum disp_dev_type device, struct disp_process_ops *ops){struct disp_process_dev *pdev = get_display_ptr(device);RET_ASSERT(DEVICE_SIZE > device);RET_ASSERT(device == pdev->dev_id);if (get_display_ops(device))printk(KERN_ERR "Warn , %s operation will be replaced \n", dev_to_str(device));spin_lock(&pdev->lock);/* set device info */set_display_ops (device, ops);spin_unlock(&pdev->lock);printk(KERN_INFO "Display %s register operation \n", dev_to_str(device));}

 

nxp-fb.c

这个文件就是与frambuffer驱动fbmem.c对接的代码。在probe时调用了register_framebuffer(info);info的数据结构定义如下:

struct fb_info {atomic_t count;int node;int flags;struct mutex lock; /* open/release/ioctl函数使用的锁 */struct mutex mm_lock; /* Lock for fb_mmap and smem_* fields */struct fb_var_screeninfo var; /* 可变参数*/struct fb_fix_screeninfo fix; /* 固定参数 */struct fb_monspecs monspecs; /* 显示器标准 */struct work_struct queue; /* Framebuffer event queue 事件队列*/struct fb_pixmap pixmap; /* Image hardware mapper图像硬件mapper */struct fb_pixmap sprite; /* Cursor hardware mapper光标硬件mapper */struct fb_cmap cmap; /* Current cmap目前颜色表 */struct list_head modelist; /* mode list */struct fb_videomode *mode; /* current mode */#ifdef CONFIG_FB_BACKLIGHT/* assigned backlight device *//* set before framebuffer registration,remove after unregister */struct backlight_device *bl_dev;/* Backlight level curve */struct mutex bl_curve_mutex;u8 bl_curve[FB_BACKLIGHT_LEVELS];#endif#ifdef CONFIG_FB_DEFERRED_IOstruct delayed_work deferred_work;struct fb_deferred_io *fbdefio;#endifstruct fb_ops *fbops;//帧缓冲操作函数fb_opsstruct device *device; /* This is the parent */struct device *dev; /* This is this fb device */int class_flag; /* private sysfs flags */#ifdef CONFIG_FB_TILEBLITTINGstruct fb_tile_ops *tileops; /* Tile Blitting */#endifchar __iomem *screen_base; /* Virtual address 虚拟基地址,大小即长*宽*每像素占字句字节数*buff个数。*/unsigned long screen_size; /* Amount of ioremapped VRAM or 0 */ io remapped虚拟内存大小。void *pseudo_palette; /* Fake palette of 16 colors */#define FBINFO_STATE_RUNNING 0#define FBINFO_STATE_SUSPENDED 1u32 state; /* Hardware state i.e suspend 硬件状态,如挂起*/void *fbcon_par; /* fbcon use-only private area *//* From here on everything is device dependent */void *par;/* we need the PCI or similar aperture base/size notsmem_start/size as smem_start may just be an objectallocated inside the aperture so may not actually overlap */struct apertures_struct {unsigned int count;struct aperture {resource_size_t base;resource_size_t size;} ranges[0];} *apertures;};

nxp_fb_probe的函数做的工作主要是初始化struct fb_info,并调用register_framebuffer(info);

static int nxp_fb_probe(struct platform_device *pdev){struct nxp_fb_plat_data *plat = pdev->dev.platform_data; // arch/arm/plat-s5p4418/dron2/device.c中定义了”nxp-fb”设备的platform_data,见上面的代码分析。struct fb_info *info = NULL;#ifdef CONFIG_FB_NXP_ION_MEMstruct nxp_fb_device *fbdev;struct nxp_fb_param *fbpar;#endifint i = 0, ret = 0;pr_debug("\n%s (name=%s, id=%d)\n", __func__, dev_name(&pdev->dev), pdev->id);/* allocate fb_info and init */info = nxp_fb_init_fb(pdev->id, &pdev->dev);if(! info) {ret = -ENOMEM;goto err_fb;}ret = nxp_fb_setup_param(pdev->id, info, plat);if (0 > ret)goto err_map;nxp_fb_setup_info(info);#ifdef CONFIG_FB_NXP_ION_MEMfbpar = info->par;fbdev = &fbpar->fb_dev;fbdev->dev = &pdev->dev;ret = nxp_fb_setup_ion(&fbpar->fb_dev.dma_buf_data);if (ret) {printk(KERN_ERR "Fail to setup ion\n");goto err_map;}#endif/* allocate frame buffer memory from here */ret = nxp_fb_alloc_mem(info);if(ret) {printk(KERN_ERR "Fail, unable to allcate frame buffer (%d)\n", pdev->id);goto err_map;}nxp_fb_init_display(info);/** device_create '/proc/fb0' & fb class* register machine file operation to frame buffer file operation* registered_fb[]* (drivers/video/fbmem.c)*/if (pdev->id != 0) {for (i = 0; pdev->id > i; i++) {if (!registered_fb[i]) {printk("FB: Reserve dev/node [%d]\n", i);registered_fb[i] = info;}}}ret = register_framebuffer(info);if(ret < 0) {printk(KERN_ERR "Fail, unable to register frame buffer(%d)\n", pdev->id);goto err_reg;}/* register to driver data, use platform_get_drvdata */platform_set_drvdata(pdev, info);return ret;err_reg:unregister_framebuffer(info);err_map:nxp_fb_free_mem(info);err_fb:nxp_fb_exit_fb(info);return ret;}

 

转载地址:https://blog.csdn.net/xgbing/article/details/102809897 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:TI Am335LCD驱动
下一篇:s5p4418分区

发表评论

最新留言

初次前来,多多关照!
[***.217.46.12]2024年03月23日 10时15分49秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章