drm 驱动是如何创建 fb device 的

Wesley13
• 阅读 963

drm 驱动是如何创建 fb device 的

什么是 drm?

drm 是一个 Linux 内核的显示系统驱动框架,区别于另外一个 DRM数字版权保护

  • drm 是一个管理 GPU 的显示框架
  • 在内核级别提供内存管理,中断处理, DMA控
  • 为应用程序提供统一的操作接口

如何使用 drm 接口

  • libdrm
  • fb device

libdrm

内核提供的 IOCTRL 太多,libdrm 用于简化编程管理当前的显示器,并修改当前的模式成为 KMS ( drm-kms - Kernel Mode-Setting

借助 libdrm 的强大 API 接口,如果内核支持 PRIME API ,也可以使用 PRIME 接口实现更为灵活的内存操作。

fb device

drm 驱动可以模拟一个 fb device, 默认是 default CRTC, 更多关于 fb device ,可以参考 内核 framebuffer 文档, fb device 是大多数 Linux 系统显示的基础。

  • The X Server, Linux 桌面系统的显示服务
  • Android gralloc, 安卓系统显示 HAL

本文讨论的问题是 drm 驱动是如何虚拟 drm crts 为 fb device

文章基于内核版本 linux-3.18

VERSION = 3
PATCHLEVEL = 18
SUBLEVEL = 0
EXTRAVERSION = -linux4sam_5.0-alpha7
NAME = Diseased Newt

drm 的代码位于:

drivers/gpu/drm/

1. 设备驱动创建 fbdev

drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c: dc->fbdev = drm_fbdev_cma_init(dev, 24,
drivers/gpu/drm/sti/sti_drm_drv.c: drm_fbdev_cma_init(dev, 32,
drivers/gpu/drm/tilcdc/tilcdc_drv.c: priv->fbdev = drm_fbdev_cma_init(dev, bpp,
drivers/gpu/drm/rcar-du/rcar_du_kms.c: fbdev = drm_fbdev_cma_init(dev, 32, dev->mode_config.num_crtc,

调用的是 drm_fbdev_cma_init

struct drm_fbdev_cma *drm_fbdev_cma_init(struct drm_device *dev,
unsigned int preferred_bpp, unsigned int num_crtc,
unsigned int max_conn_count)
{
struct drm_fbdev_cma *fbdev_cma;
struct drm_fb_helper *helper;
int ret;

fbdev_cma = kzalloc(sizeof(*fbdev_cma), GFP_KERNEL);

...
helper = &fbdev_cma->fb_helper;

drm_fb_helper_prepare(dev, helper, &drm_fb_cma_helper_funcs);

...
ret = drm_fb_helper_initial_config(helper, preferred_bpp);
    if (ret < 0) {
        dev_err(dev->dev, "Failed to set initial hw configuration.\n");
    goto err_drm_fb_helper_fini;
}

return fbdev_cma;

其中最重要的数据结构是 drm_fb_helper_funcs

static const struct drm_fb_helper_funcs drm_fb_cma_helper_funcs = {
.fb_probe = drm_fbdev_cma_create,

};

2. 完成 fb 设备的创建:

static int drm_fbdev_cma_create(struct drm_fb_helper *helper,
    struct drm_fb_helper_surface_size *sizes)
{
    struct drm_fbdev_cma *fbdev_cma = to_fbdev_cma(helper);
    struct drm_mode_fb_cmd2 mode_cmd = { 0 };
    struct drm_device *dev = helper->dev;
    struct drm_gem_cma_object *obj;
    struct drm_framebuffer *fb;
    unsigned int bytes_per_pixel;
    unsigned long offset;
    struct fb_info *fbi;
    size_t size;
    int ret;

    DRM_DEBUG_KMS("surface width(%d), height(%d) and bpp(%d)\n",
            sizes->surface_width, sizes->surface_height,
            sizes->surface_bpp);

    bytes_per_pixel = DIV_ROUND_UP(sizes->surface_bpp, 8);

    mode_cmd.width = sizes->surface_width;
    mode_cmd.height = sizes->surface_height;
    mode_cmd.pitches[0] = sizes->surface_width * bytes_per_pixel;
    mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
        sizes->surface_depth);

    size = mode_cmd.pitches[0] * mode_cmd.height;
    obj = drm_gem_cma_create(dev, size);
    if (IS_ERR(obj))
        return -ENOMEM;

    fbi = framebuffer_alloc(0, dev->dev);
    if (!fbi) {
        dev_err(dev->dev, "Failed to allocate framebuffer info.\n");
        ret = -ENOMEM;
        goto err_drm_gem_cma_free_object;
    }

    fbdev_cma->fb = drm_fb_cma_alloc(dev, &mode_cmd, &obj, 1);
    if (IS_ERR(fbdev_cma->fb)) {
        dev_err(dev->dev, "Failed to allocate DRM framebuffer.\n");
        ret = PTR_ERR(fbdev_cma->fb);
        goto err_framebuffer_release;
    }

    fb = &fbdev_cma->fb->fb;
    helper->fb = fb;
    helper->fbdev = fbi;

    fbi->par = helper;
    fbi->flags = FBINFO_FLAG_DEFAULT;
    fbi->fbops = &drm_fbdev_cma_ops;

    ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
    if (ret) {
        dev_err(dev->dev, "Failed to allocate color map.\n");
        goto err_drm_fb_cma_destroy;
    }

    drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth);
    drm_fb_helper_fill_var(fbi, helper, fb->width, fb->height);

    offset = fbi->var.xoffset * bytes_per_pixel;
    offset += fbi->var.yoffset * fb->pitches[0];

    dev->mode_config.fb_base = (resource_size_t)obj->paddr;
    fbi->screen_base = obj->vaddr + offset;
    fbi->fix.smem_start = (unsigned long)(obj->paddr + offset);
    fbi->screen_size = size;
    fbi->fix.smem_len = size;

    return 0;

err_drm_fb_cma_destroy:
    drm_framebuffer_unregister_private(fb);
    drm_fb_cma_destroy(fb);
err_framebuffer_release:
    framebuffer_release(fbi);
err_drm_gem_cma_free_object:
    drm_gem_cma_free_object(&obj->base);
    return ret;
}

流程图

Created with Raphaël 2.1.0 drm_fbdev_cma_init drm_fb_helper_initial_config drm_fb_helper_single_fb_probe register_framebuffer

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Wesley13 Wesley13
2年前
java将前端的json数组字符串转换为列表
记录下在前端通过ajax提交了一个json数组的字符串,在后端如何转换为列表。前端数据转化与请求varcontracts{id:'1',name:'yanggb合同1'},{id:'2',name:'yanggb合同2'},{id:'3',name:'yang
Easter79 Easter79
2年前
swap空间的增减方法
(1)增大swap空间去激活swap交换区:swapoff v /dev/vg00/lvswap扩展交换lv:lvextend L 10G /dev/vg00/lvswap重新生成swap交换区:mkswap /dev/vg00/lvswap激活新生成的交换区:swapon v /dev/vg00/lvswap
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
2年前
Java日期时间API系列36
  十二时辰,古代劳动人民把一昼夜划分成十二个时段,每一个时段叫一个时辰。二十四小时和十二时辰对照表:时辰时间24时制子时深夜11:00凌晨01:0023:0001:00丑时上午01:00上午03:0001:0003:00寅时上午03:00上午0
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Android蓝牙连接汽车OBD设备
//设备连接public class BluetoothConnect implements Runnable {    private static final UUID CONNECT_UUID  UUID.fromString("0000110100001000800000805F9B34FB");
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
4个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这