drm 驱动是如何创建 fb device 的

drm 驱动是如何创建 fb device 的

  • drm 驱动是如何创建 fb device 的
    • 什么是 drm
    • 如何使用 drm 接口
      • libdrm
      • fb device
    • 本文讨论的问题是 drm 驱动是如何虚拟 drm crts 为 fb device
      • 设备驱动创建 fbdev
      • 完成 fb 设备的创建
    • 流程图

什么是 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

你可能感兴趣的:(linux,框架,内核,drm)