Framebuffer 驱动

实验环境:
正点原子alpha 开发板
调试自己编写的framebuffer 驱动,加载到内核之后,显示出小企鹅

1. Framebufer 总体框架

在这里插入图片描述fbmem.c 作为Framebuffer的核心层,向上提供app使用的接口,向下屏蔽了底层各种硬件的差异;
在这里插入图片描述
准确来说fbmem.c 就是一个字符设备驱动框架的程序,对于字符设备驱动框架的程序如下:
(1) 分配主次设备号:如果主设备号为0,则内核自动分配;
(2)构造file_ops 结构体,提供应用层使用到的常用接口:drv_open, drv_read, drv_write, drv_ioctrl等;
(3)将主次设备号和构造的结构体注册到内核:使用register_char_dev()接口;
(4) 通过module_init(), module_exit() 完成驱动程序的自动化调用;
(5)使用其他的一些函数class_create 和 device_create 自动创建出设备节点;
fbmem.c 就是完成了以上字符设备驱动的通用的操作,但是具体对硬件的操作对于imx6ull开发板来说就是 mxsfb.c驱动。

fbmem.c 对下提供了注册fbinfo 的接口函数:register_framebuffer(struct fb_info *fb_info);
底层硬件驱动通过调用此函数向 fbmem.c 提供了统一的接口操作函数。

2. mxsfb.c 驱动框架

mxsfb.c 通过平台总线的方式被内核管理,即通过platform_driver, 如下:

static struct platform_driver mxsfb_driver = {
 .probe = mxsfb_probe,
 .remove = mxsfb_remove,
 .shutdown = mxsfb_shutdown,
 .id_table = mxsfb_devtype,
 .driver = {
 	   .name = DRIVER_NAME,
 	   .of_match_table = mxsfb_dt_ids,
 	   .pm = &mxsfb_pm_ops,
 },
};

module_platform_driver(mxsfb_driver);

当of_match_table与内核中某个设备节点匹配之后,mxsfb_probe 就会被调用;

mxsfb_probe主要完成的功能如下:

1. 申请fb_info 
2. 初始化fbinfo 结构体中的各个成员变量
3. 初始化lcdif控制器
4. 使用register_framebuffer() 函数向linux内核注册初始化号的fbinfo.

3. 结合以上分析 自己实现的驱动如下:

#include <linux/busfreq-imx.h>
#include <linux/console.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/interrupt.h>
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/io.h>
#include <linux/pinctrl/consumer.h>
#include <linux/fb.h>
#include <linux/mxcfb.h>
#include <linux/regulator/consumer.h>
#include <video/of_display_timing.h>
#include <video/videomode.h>
#include <linux/uaccess.h>


static struct fb_info *lcdfb_info;

static struct imx6ull_elcdif *elcdif;
static struct clk *clk_pix;
static struct clk *clk_axi;
static uint32_t pseudo_palette[16];


/** LCDIF - Register Layout Typedef */
struct imx6ull_elcdif{
  volatile unsigned int CTRL;                              /**< eLCDIF General Control Register, offset: 0x0 */
  volatile unsigned int CTRL_SET;                          /**< eLCDIF General Control Register, offset: 0x4 */
  volatile unsigned int CTRL_CLR;                          /**< eLCDIF General Control Register, offset: 0x8 */
  volatile unsigned int CTRL_TOG;                          /**< eLCDIF General Control Register, offset: 0xC */
  volatile unsigned int CTRL1;                             /**< eLCDIF General Control1 Register, offset: 0x10 */
  volatile unsigned int CTRL1_SET;                         /**< eLCDIF General Control1 Register, offset: 0x14 */
  volatile unsigned int CTRL1_CLR;                         /**< eLCDIF General Control1 Register, offset: 0x18 */
  volatile unsigned int CTRL1_TOG;                         /**< eLCDIF General Control1 Register, offset: 0x1C */
  volatile unsigned int CTRL2;                             /**< eLCDIF General Control2 Register, offset: 0x20 */
  volatile unsigned int CTRL2_SET;                         /**< eLCDIF General Control2 Register, offset: 0x24 */
  volatile unsigned int CTRL2_CLR;                         /**< eLCDIF General Control2 Register, offset: 0x28 */
  volatile unsigned int CTRL2_TOG;                         /**< eLCDIF General Control2 Register, offset: 0x2C */
  volatile unsigned int TRANSFER_COUNT;                    /**< eLCDIF Horizontal and Vertical Valid Data Count Register, offset: 0x30 */
       unsigned char RESERVED_0[12];
  volatile unsigned int CUR_BUF;                           /**< LCD Interface Current Buffer Address Register, offset: 0x40 */
       unsigned char RESERVED_1[12];
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值