Linux驱动分析之LCD驱动架构

简介: 在Linux设备中,LCD显示采用了帧缓冲(framebuffer)技术,所以LCD驱动也叫Framebuffer驱动,所以LCD驱动框架就是围绕帧缓冲展开工作。帧缓冲(framebuffer)是Linux系统为显示设备提供的一个接口,它将显示缓冲区抽象出来,屏蔽图像硬件的底层差异,允许上层应用程序在图形模式下直接对显示缓冲区进行读写操作。对于帧缓冲设备而言,只要在显示缓冲区中与显示点对应的区域写入颜色值,对应的颜色会自动在屏幕上显示。帧缓冲为标准字符设备, 主设备号为29,对应于/dev/fbn。

Framebuffer简介

   在Linux设备中,LCD显示采用了帧缓冲(framebuffer)技术,所以LCD驱动也叫Framebuffer驱动,所以LCD驱动框架就是围绕帧缓冲展开工作。帧缓冲(framebuffer)是Linux系统为显示设备提供的一个接口,它将显示缓冲区抽象出来,屏蔽图像硬件的底层差异,允许上层应用程序在图形模式下直接对显示缓冲区进行读写操作。对于帧缓冲设备而言,只要在显示缓冲区中与显示点对应的区域写入颜色值,对应的颜色会自动在屏幕上显示。帧缓冲为标准字符设备, 主设备号为29,对应于/dev/fbn。


Framebuffer框架结构

aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy9NNm5FQktsN1dDTVpjQlBuN1BlWEpCc2JpY2huY0VRRFFYMGYxS0h2emVXUjZGc1g5clZ3bjUxeXlpY0oydFJ2c05rNmxUT1pFZUlCT2FmalRoVEo0em13LzY0MA.png

    核心层代码fbmem.c向上提供了完整的字符设备操作接口,也就是实现注册字符设备,提供通用的open,read,write,ioctl,mmap等接口;向下给硬件设备驱动层提供标准的驱动编程接口。

   在linux系统中,一个硬件控制器(显卡)抽象为一个fb_info结构体,要实现一个LCD驱动就是要实现这个结构,并且使用核心层提供的注册函数注册。


重要结构体

内核版本:4.20.12

  • fb_info
// include/linux/fb.hstructfb_info {
atomic_tcount;
intnode;
intflags;
intfbcon_rotate_hint;
structmutexlock;    /* open/release/ioctl中使用*/structmutexmm_lock;    /*fb_mmap和smem_*数据域中使用 */structfb_var_screeninfovar;  /* LCD屏可变参数 */structfb_fix_screeninfofix;  /* LCD屏固定参数 */structfb_monspecsmonspecs;  /* Current Monitor specs */structwork_structqueue;  /* Framebuffer event queue */structfb_pixmappixmap;  /* Image hardware mapper */structfb_pixmapsprite;  /* Cursor hardware mapper */structfb_cmapcmap;    /* Current cmap */structlist_headmodelist;      /* mode list */structfb_videomode*mode;  /* current mode */#ifdef CONFIG_FB_BACKLIGHTstructbacklight_device*bl_dev; //背光设备structmutexbl_curve_mutex;  
u8bl_curve[FB_BACKLIGHT_LEVELS]; //背光水平曲线#endif#ifdef CONFIG_FB_DEFERRED_IOstructdelayed_workdeferred_work;
structfb_deferred_io*fbdefio;
#endifstructfb_ops*fbops;          /*真正操作硬件寄存器的方法集合*/structdevice*device;  
structdevice*dev;            /* fb设备*/intclass_flag;                    /* private sysfs flags */#ifdef CONFIG_FB_TILEBLITTINGstructfb_tile_ops*tileops;    /* Tile Blitting */#endifunion {
char__iomem*screen_base;  /* LCD虚拟显存地址 */char*screen_buffer;
  };
unsignedlongscreen_size;  /* LCD虚拟显存大小 */void*pseudo_palette;    /* 指向16种颜色的调试板,其实就是一块内存*/#define FBINFO_STATE_RUNNING  0#define FBINFO_STATE_SUSPENDED  1u32state;      /* Hardware state i.e suspend */void*fbcon_par;
void*par; //私有数据,用来存放自己的数据的结构地址structapertures_struct {
unsignedintcount;
structaperture {
resource_size_tbase;
resource_size_tsize;
    } ranges[0];
  } *apertures;
boolskip_vt_switch; /* no VT switch on suspend/resume required */};

使用标准的LCD框架编写,var, fix, fbops, screen_base这四个成员是一定要实现的。

  • fb_var_screeninfo
structfb_var_screeninfo {
__u32xres;      /* 可见屏幕一行有多少像素点     */__u32yres;                     /*可见屏幕一屏有多少行,也就是列*/__u32xres_virtual;    /* 虚拟屏幕一行有多少像素点*/__u32yres_virtual;             /*虚拟屏幕一屏有多少行*///显存大小并不一定等于实际屏幕显示对应的区域__u32xoffset;      /* 虚拟屏到实际屏的水平偏移量 */__u32yoffset;      /* 虚拟屏到实际屏的垂直偏移量*/__u32bits_per_pixel;    /* 每个像素的位数即BPP,比如:RGB565则填入16*/__u32grayscale;    /* 0 = 彩色, 1 = 灰度屏*//* >1 = FOURCC      */structfb_bitfieldred;    /* 红色的长度和偏移信息  */structfb_bitfieldgreen;  /* 绿色的长度和偏移信息 */structfb_bitfieldblue;        /* 蓝色的长度和偏移信息 */structfb_bitfieldtransp;  /* 透明色的长度和偏移信息*/__u32nonstd;      /* 不等于0则为非标准像素格式 *///定义修改参数生效时刻,一般马上生效,对应值是0,宏名是 FB_ACTIVATE_NOW__u32activate;      /* see FB_ACTIVATE_*    *///存放物理屏的物理尺寸,是外观尺寸,单位是mm,可选择填充的项  非重点__u32height;      /* height of picture in mm    */__u32width;      /* width of picture in mm     */__u32accel_flags;    /* (OBSOLETE) see fb_info.flags *///下面是LCD屏的工作时序,参数从datasheet来__u32pixclock;      /* pixel clock in ps (pico seconds) */__u32left_margin;    /* time from sync to picture  */__u32right_margin;    /* time from picture to sync  */__u32upper_margin;    /* time from sync to picture  */__u32lower_margin;
__u32hsync_len;    /* length of horizontal sync  */__u32vsync_len;    /* length of vertical sync  */__u32sync;      /* see FB_SYNC_*    */__u32vmode;      /* see FB_VMODE_*    */__u32rotate;      /* angle we rotate counter clockwise */__u32colorspace;    /* colorspace for FOURCC-based modes */__u32reserved[4];    /* Reserved for future compatibility */};

上面结构体的参数大部分都是要从LCD屏的datasheet中获取。

  • fb_fix_screeninfo
structfb_fix_screeninfo {
charid[16];      /* LCD标识名 填写一个16字符以内字符串即可 */unsignedlongsmem_start;  /* 显存的物理起始地址,不是虚拟地址*//* (physical address) */__u32smem_len;      /* 显存的内存长度 */__u32type;      /* 表示像素类型 see FB_TYPE_*  */__u32type_aux;      /* Interleave for interleaved Planes */__u32visual;      /* 表示颜色类型 see FB_VISUAL_*  */__u16xpanstep;      /* 如果没有硬件panning就赋值为0  */__u16ypanstep;      /* 如果没有硬件panning就赋值为0  */__u16ywrapstep;    /* 如果没有硬件panning就赋值为0  *///一行的字节数 ,例:(RGB565)240*320,那么这里就等于240*16/8  __u32line_length;    /* length of a line in bytes    */unsignedlongmmio_start;  /* Start of Memory Mapped I/O   *//* (physical address) *///独立显卡相关的,基本不用__u32mmio_len;      /* Length of Memory Mapped I/O  */__u32accel;      /* Indicate to driver which  *//*  specific chip/card we have  */__u16capabilities;    /* see FB_CAP_*      */__u16reserved[2];    /* Reserved for future compatibility */};
  • fb_ops
structfb_ops {
/* open/release and usage marking */structmodule*owner;
int (*fb_open)(structfb_info*info, intuser);
int (*fb_release)(structfb_info*info, intuser);
/* For framebuffers with strange non linear layouts or that do not* work with normal memory mapped access*/ssize_t (*fb_read)(structfb_info*info, char__user*buf,
size_tcount, loff_t*ppos);
ssize_t (*fb_write)(structfb_info*info, constchar__user*buf,
size_tcount, loff_t*ppos);
/* checks var and eventually tweaks it to something supported,* DO NOT MODIFY PAR */int (*fb_check_var)(structfb_var_screeninfo*var, structfb_info*info);
/* set the video mode according to info->var */int (*fb_set_par)(structfb_info*info);
/* set color register */int (*fb_setcolreg)(unsignedregno, unsignedred, unsignedgreen,
unsignedblue, unsignedtransp, structfb_info*info);
/* set color registers in batch */int (*fb_setcmap)(structfb_cmap*cmap, structfb_info*info);
/* blank display */int (*fb_blank)(intblank, structfb_info*info);
/* pan display */int (*fb_pan_display)(structfb_var_screeninfo*var, structfb_info*info);
/* Draws a rectangle */void (*fb_fillrect) (structfb_info*info, conststructfb_fillrect*rect);
/* Copy data from area to another */void (*fb_copyarea) (structfb_info*info, conststructfb_copyarea*region);
/* Draws a image to the display */void (*fb_imageblit) (structfb_info*info, conststructfb_image*image);
/* Draws cursor */int (*fb_cursor) (structfb_info*info, structfb_cursor*cursor);
/* wait for blit idle, optional */int (*fb_sync)(structfb_info*info);
/* perform fb specific ioctl (optional) */int (*fb_ioctl)(structfb_info*info, unsignedintcmd,
unsignedlongarg);
/* Handle 32bit compat ioctl (optional) */int (*fb_compat_ioctl)(structfb_info*info, unsignedcmd,
unsignedlongarg);
/* perform fb specific mmap */int (*fb_mmap)(structfb_info*info, structvm_area_struct*vma);
/* get capability given var */void (*fb_get_caps)(structfb_info*info, structfb_blit_caps*caps,
structfb_var_screeninfo*var);
/* teardown any resources to do with this framebuffer */void (*fb_destroy)(structfb_info*info);
/* called at KDB enter and leave time to prepare the console */int (*fb_debug_enter)(structfb_info*info);
int (*fb_debug_leave)(structfb_info*info);
};

常用的重要成员:

  • fb_open:当你的lcd不需要做什么特殊的初始化操作,这个方法可以不实现
  • fb_release:当你的应用程序不使用lcd设备的时候,需要做的事情在这里实现
  • fb_read:当你的lcd控制器使用的内存是独立显存的时候才需要使用,直接使用核心层read
  • fb_write:当你的lcd控制器使用的内存是独立显存的时候才需要使用,直接使用核心层write
  • fb_check_var:检测应用程序传递下来的可变参数是否合法。当你不提供给应用程序通过ioctl命令动态修改LCD可变参数时不需要实现。
  • fb_set_par:实现的功能是把可变参数设置到硬件寄存器中去
  • fb_blank:实现屏幕的黑屏白屏模式(开屏,关屏)
  • fb_fillrect:实现功能是填充矩形
  • fb_copyarea:实现功能是区域复制
  • fb_imageblit:实现功能是绘制位图
  • fb_mmap:实现的功能是把内核空间的分配的显存映射到用户空间中对应的mmap系统调用,当你的控制器是独显的时候才需要


API函数

/*函数功能:注册fb_info*/intregister_framebuffer(structfb_info*fb_info)
/*函数功能:注销fb_info*/intunregister_framebuffer(structfb_info*fb_info)
/*函数功能:动态分配DMA内存,同时可以得到分配内存的虚拟地址和物理地址 参数说明: dev:设备指针如果没有赋值NULL size:内存大小 dma_handle:作为输出参数使用,存放分配到的内存对应的物理地址 flag:内存分配方式 返回值:分配到的内存的首地址*/void*dma_alloc_writecombine(structdevice*dev, size_tsize,
dma_addr_t*dma_handle, gfp_tflag)
/*功能:释放由dma_alloc_writecombine分配的dma内存 参数: dev:设备指针如果没有赋值NULL size:内存大小 cpu_addr:dma_alloc_writecombine得到的虚拟地址首地址 dma_handle:作为输出参数使用,存放分配到的内存对应的物理地址 */voiddma_free_writecombine(structdevice*dev, size_tsize,
void*cpu_addr, dma_addr_tdma_handle)  

lcd每屏显示的数据量很大,所以lcd一般是利用DMA来搬运数据,而DMA模块只会使用物理地址,所以LCD驱动中需要记录物理地址。


总结

   上面的结构体中有很多参数,对于一些普通的LCD屏,需要用到的参数并不多。主要就是从数据手册中获取屏幕参数信息,填充fb_info,然后注册。另一部分就LCDC的寄存器配置。目前很多原厂会将这两部分进行分离,这样就更方便客户进行定制。


相关文章
|
3月前
|
安全 数据处理 数据安全/隐私保护
C/S架构与B/S架构的适用场景分析
C/S架构(客户端/服务器架构)与B/S架构(浏览器/服务器架构)在适用场景上各有特点,主要取决于应用的具体需求、用户群体、系统维护成本、跨平台需求等因素。
281 6
|
1月前
|
存储 SQL Apache
Apache Doris 开源最顶级基于MPP架构的高性能实时分析数据库
Apache Doris 是一个基于 MPP 架构的高性能实时分析数据库,以其极高的速度和易用性著称。它支持高并发点查询和复杂分析场景,适用于报表分析、即席查询、数据仓库和数据湖查询加速等。最新发布的 2.0.2 版本在性能、稳定性和多租户支持方面有显著提升。社区活跃,已广泛应用于电商、广告、用户行为分析等领域。
Apache Doris 开源最顶级基于MPP架构的高性能实时分析数据库
|
1月前
|
Java Linux Android开发
深入探索Android系统架构:从Linux内核到应用层
本文将带领读者深入了解Android操作系统的复杂架构,从其基于Linux的内核到丰富多彩的应用层。我们将探讨Android的各个关键组件,包括硬件抽象层(HAL)、运行时环境、以及核心库等,揭示它们如何协同工作以支持广泛的设备和应用。通过本文,您将对Android系统的工作原理有一个全面的认识,理解其如何平衡开放性与安全性,以及如何在多样化的设备上提供一致的用户体验。
|
1月前
|
缓存 运维 网络协议
深入Linux内核架构:操作系统的核心奥秘
深入Linux内核架构:操作系统的核心奥秘
52 2
|
1月前
|
运维 NoSQL Java
后端架构演进:微服务架构的优缺点与实战案例分析
【10月更文挑战第28天】本文探讨了微服务架构与单体架构的优缺点,并通过实战案例分析了微服务架构在实际应用中的表现。微服务架构具有高内聚、低耦合、独立部署等优势,但也面临分布式系统的复杂性和较高的运维成本。通过某电商平台的实际案例,展示了微服务架构在提升系统性能和团队协作效率方面的显著效果,同时也指出了其带来的挑战。
76 4
|
19天前
|
缓存 算法 Linux
Linux内核中的调度策略优化分析####
本文深入探讨了Linux操作系统内核中调度策略的工作原理,分析了不同调度算法(如CFS、实时调度)在多核处理器环境下的性能表现,并提出了针对高并发场景下调度策略的优化建议。通过对比测试数据,展示了调度策略调整对于系统响应时间及吞吐量的影响,为系统管理员和开发者提供了性能调优的参考方向。 ####
|
2月前
|
存储 SQL 分布式计算
湖仓一体架构深度解析:构建企业级数据管理与分析的新基石
【10月更文挑战第7天】湖仓一体架构深度解析:构建企业级数据管理与分析的新基石
135 1
|
3月前
|
存储 监控 安全
SaaS业务架构:业务能力分析
【9月更文挑战第20天】在数字化时代,软件即服务(SaaS)模式逐渐成为企业软件解决方案的首选。SaaS 业务架构设计对于提供高效、可靠的服务至关重要。其核心业务能力包括:用户管理(注册登录、角色权限)、数据管理(存储备份、安全共享)、业务流程管理(设计定制、工作流自动化)、应用集成(第三方应用、移动应用)及客户服务(支持培训、反馈改进)。通过优化这些能力,可为企业提供更高效、可靠的 SaaS 服务。
67 11
|
3月前
|
编解码 Linux 开发工具
Linux平台x86_64|aarch64架构RTMP推送|轻量级RTSP服务模块集成说明
支持x64_64架构、aarch64架构(需要glibc-2.21及以上版本的Linux系统, 需要libX11.so.6, 需要GLib–2.0, 需安装 libstdc++.so.6.0.21、GLIBCXX_3.4.21、 CXXABI_1.3.9)。
|
3月前
|
存储 传感器 Linux
STM32微控制器为何不适合运行Linux系统的分析
总的来说,虽然技术上可能存在某些特殊情况下将Linux移植到高端STM32微控制器上的可能性,但从资源、性能、成本和应用场景等多个方面考虑,STM32微控制器不适合运行Linux系统。对于需要运行Linux的应用,更适合选择ARM Cortex-A系列处理器的开发平台。
281 0