MIPI DSI 【三】BRING UP

一、概述


书接上文,前边提到了所有子模块要开始启动了,master调用了rockchip_drm_bind函数。

二、结构体


2.1 rockchip_drm_driver结构体

static struct drm_driver rockchip_drm_driver = {
    .driver_features        = DRIVER_MODESET | DRIVER_GEM |
                              DRIVER_PRIME | DRIVER_ATOMIC |
                              DRIVER_RENDER,
    .postclose              = rockchip_drm_postclose,
    .lastclose              = rockchip_drm_lastclose,
    .open                   = rockchip_drm_open,
    .gem_vm_ops             = &drm_gem_cma_vm_ops,
    .gem_free_object_unlocked = rockchip_gem_free_object,
    .dumb_create            = rockchip_gem_dumb_create,
    .dumb_map_offset        = rockchip_gem_dumb_map_offset,
    .dumb_destroy           = drm_gem_dumb_destroy,
    .prime_handle_to_fd     = drm_gem_prime_handle_to_fd,
    .prime_fd_to_handle     = drm_gem_prime_fd_to_handle,
    .gem_prime_import       = drm_gem_prime_import,
    .gem_prime_export       = drm_gem_prime_export,
    .gem_prime_get_sg_table = rockchip_gem_prime_get_sg_table,
    .gem_prime_import_sg_table      = rockchip_gem_prime_import_sg_table,
    .gem_prime_vmap         = rockchip_gem_prime_vmap,
    .gem_prime_vunmap       = rockchip_gem_prime_vunmap,
    .gem_prime_mmap         = rockchip_gem_mmap_buf,
    .gem_prime_begin_cpu_access = rockchip_gem_prime_begin_cpu_access,
    .gem_prime_end_cpu_access = rockchip_gem_prime_end_cpu_access,
#ifdef CONFIG_DEBUG_FS
    .debugfs_init           = rockchip_drm_debugfs_init,
#endif
    .ioctls                 = rockchip_ioctls,
    .num_ioctls             = ARRAY_SIZE(rockchip_ioctls),
    .fops                   = &rockchip_drm_driver_fops,
    .name   = DRIVER_NAME,
    .desc   = DRIVER_DESC,
    .date   = DRIVER_DATE,
    .major  = DRIVER_MAJOR,
    .minor  = DRIVER_MINOR,
    .patchlevel     = DRIVER_PATCH,
};

2.2 struct drm_device 【drm_device.h】
2.3 struct drm_driver【drm_drv.h】

三、源码分析


3.1 rockchip_drm_bind函数分析
由这个函数的代码量就可以看出来这是个办大事儿的函数

static int rockchip_drm_bind(struct device *dev)
{
     struct drm_device *drm_dev;
     struct rockchip_drm_private *private;
     int ret;
     struct device_node *np = dev->of_node;
     struct device_node *parent_np;
     struct drm_crtc *crtc;
//3.1.1 分配一个新的drm_device
     drm_dev = drm_dev_alloc(&rockchip_drm_driver, dev);
     if (IS_ERR(drm_dev))
             return PTR_ERR(drm_dev);

     dev_set_drvdata(dev, drm_dev);

     private = devm_kzalloc(drm_dev->dev, sizeof(*private), GFP_KERNEL);
     if (!private) {
             ret = -ENOMEM;
             goto err_free;
     }

     mutex_init(&private->commit_lock);
     INIT_WORK(&private->commit_work, rockchip_drm_atomic_work);
     drm_dev->dev_private = private;

     private->dmc_support = false;
     private->devfreq = devfreq_get_devfreq_by_phandle(dev, 0);
     if (IS_ERR(private->devfreq)) {
             if (PTR_ERR(private->devfreq) == -EPROBE_DEFER) {
                     parent_np = of_parse_phandle(np, "devfreq", 0);
                     if (parent_np &&
                         of_device_is_available(parent_np)) {
                             private->dmc_support = true;
                             dev_warn(dev, "defer getting devfreq\n");
                     } else {
                            dev_info(dev, "dmc is disabled\n");
                     }
             } else {
                     dev_info(dev, "devfreq is not set\n");
             }
             private->devfreq = NULL;
     } else {
             private->dmc_support = true;
             dev_info(dev, "devfreq is ready\n");
     }
     private->hdmi_pll.pll = devm_clk_get(dev, "hdmi-tmds-pll");
     if (PTR_ERR(private->hdmi_pll.pll) == -ENOENT) {
             private->hdmi_pll.pll = NULL;
     } else if (PTR_ERR(private->hdmi_pll.pll) == -EPROBE_DEFER) {
             ret = -EPROBE_DEFER;
             goto err_free;
     } else if (IS_ERR(private->hdmi_pll.pll)) {
             dev_err(dev, "failed to get hdmi-tmds-pll\n");
             ret = PTR_ERR(private->hdmi_pll.pll);
             goto err_free;
     }
     private->default_pll.pll = devm_clk_get(dev, "default-vop-pll");
     if (PTR_ERR(private->default_pll.pll) == -ENOENT) {
             private->default_pll.pll = NULL;
     } else if (PTR_ERR(private->default_pll.pll) == -EPROBE_DEFER) {
             ret = -EPROBE_DEFER;
             goto err_free;
     } else if (IS_ERR(private->default_pll.pll)) {
             dev_err(dev, "failed to get default vop pll\n");
             ret = PTR_ERR(private->default_pll.pll);
             goto err_free;
     }

     INIT_LIST_HEAD(&private->psr_list);
     mutex_init(&private->psr_list_lock);

     ret = rockchip_drm_init_iommu(drm_dev);
     if (ret)
             goto err_free;

     drm_mode_config_init(drm_dev);

     rockchip_drm_mode_config_init(drm_dev);
     rockchip_drm_create_properties(drm_dev);
     /* Try to bind all sub drivers. */
     ret = component_bind_all(dev, drm_dev);
     if (ret)
             goto err_mode_config_cleanup;

     rockchip_attach_connector_property(drm_dev);
     ret = drm_vblank_init(drm_dev, drm_dev->mode_config.num_crtc);
     if (ret)
             goto err_unbind_all;

     drm_mode_config_reset(drm_dev);
     rockchip_drm_set_property_default(drm_dev);

     /*
      * enable drm irq mode.
      * - with irq_enabled = true, we can use the vblank feature.
      */
     drm_dev->irq_enabled = true;

     /* init kms poll for handling hpd */
     drm_kms_helper_poll_init(drm_dev);

     rockchip_gem_pool_init(drm_dev);
#ifndef MODULE
     show_loader_logo(drm_dev);
#endif
     ret = of_reserved_mem_device_init(drm_dev->dev);
     if (ret)
             DRM_DEBUG_KMS("No reserved memory region assign to drm\n");

     ret = rockchip_drm_fbdev_init(drm_dev);
     if (ret)
             goto err_kms_helper_poll_fini;

     drm_for_each_crtc(crtc, drm_dev) {
             struct drm_fb_helper *helper = private->fbdev_helper;
             struct rockchip_crtc_state *s = NULL;

             if (!helper)
                     break;

             s = to_rockchip_crtc_state(crtc->state);
             if (is_support_hotplug(s->output_type))
                     drm_framebuffer_get(helper->fb);
     }

     drm_dev->mode_config.allow_fb_modifiers = true;

     ret = drm_dev_register(drm_dev, 0);
     if (ret)
             goto err_fbdev_fini;

     return 0;
err_fbdev_fini:
     rockchip_drm_fbdev_fini(drm_dev);
err_kms_helper_poll_fini:
     rockchip_gem_pool_destroy(drm_dev);
     drm_kms_helper_poll_fini(drm_dev);
     drm_vblank_cleanup(drm_dev);
err_unbind_all:
     component_unbind_all(dev, drm_dev);
err_mode_config_cleanup:
     drm_mode_config_cleanup(drm_dev);
     rockchip_iommu_cleanup(drm_dev);
err_free:
     drm_dev->dev_private = NULL;
     dev_set_drvdata(dev, NULL);
     drm_dev_put(drm_dev);
     return ret;
}

3.1.1 drm_dev_alloc

struct drm_device *drm_dev_alloc(struct drm_driver *driver,
                                 struct device *parent)
{
     struct drm_device *dev;
     int ret;
//分配drm_device结构内存
     dev = kzalloc(sizeof(*dev), GFP_KERNEL);
     if (!dev)
             return ERR_PTR(-ENOMEM);

     ret = drm_dev_init(dev, driver, parent);
     if (ret) {
             kfree(dev);
             return ERR_PTR(ret);
     }

     return dev;
}

3.1.1.1 drm_dev_init函数分析
//

int drm_dev_init(struct drm_device *dev,
                 struct drm_driver *driver,
                 struct device *parent)
{
    int ret;

    if (!drm_core_init_complete) {
            DRM_ERROR("DRM core is not initialized\n");
            return -ENODEV;
    }

    kref_init(&dev->ref);
    dev->dev = get_device(parent);
    dev->driver = driver;

    INIT_LIST_HEAD(&dev->filelist);
    INIT_LIST_HEAD(&dev->filelist_internal);
    INIT_LIST_HEAD(&dev->clientlist);
    INIT_LIST_HEAD(&dev->ctxlist);
    INIT_LIST_HEAD(&dev->vmalist);
    INIT_LIST_HEAD(&dev->maplist);
    INIT_LIST_HEAD(&dev->vblank_event_list);

    spin_lock_init(&dev->buf_lock);
    spin_lock_init(&dev->event_lock);
    mutex_init(&dev->struct_mutex);
    mutex_init(&dev->filelist_mutex);
    mutex_init(&dev->clientlist_mutex);
    mutex_init(&dev->ctxlist_mutex);
    mutex_init(&dev->master_mutex);

    dev->anon_inode = drm_fs_inode_new();
    if (IS_ERR(dev->anon_inode)) {
            ret = PTR_ERR(dev->anon_inode);
            DRM_ERROR("Cannot allocate anonymous inode: %d\n", ret);
            goto err_free;
    }

    if (drm_core_check_feature(dev, DRIVER_RENDER)) {
            ret = drm_minor_alloc(dev, DRM_MINOR_RENDER);
            if (ret)
                    goto err_minors;
    }

    ret = drm_minor_alloc(dev, DRM_MINOR_PRIMARY);
    if (ret)
            goto err_minors;

    ret = drm_ht_create(&dev->map_hash, 12);
    if (ret)
            goto err_minors;

    drm_legacy_ctxbitmap_init(dev);

    if (drm_core_check_feature(dev, DRIVER_GEM)) {
            ret = drm_gem_init(dev);
            if (ret) {
                    DRM_ERROR("Cannot initialize graphics execution manager (GEM)\n");
                    goto err_ctxbitmap;
            }
    }

    /* Use the parent device name as DRM device unique identifier, but fall
     * back to the driver name for virtual devices like vgem. */
    ret = drm_dev_set_unique(dev, parent ? dev_name(parent) : driver->name);
    if (ret)
            goto err_setunique;

    return 0;

err_setunique:
    if (drm_core_check_feature(dev, DRIVER_GEM))
            drm_gem_destroy(dev);
err_ctxbitmap:
    drm_legacy_ctxbitmap_cleanup(dev);
    drm_ht_remove(&dev->map_hash);
err_minors:
    drm_minor_free(dev, DRM_MINOR_PRIMARY);
    drm_minor_free(dev, DRM_MINOR_RENDER);
    drm_fs_inode_free(dev->anon_inode);
err_free:
    put_device(dev->dev);
    mutex_destroy(&dev->master_mutex);
    mutex_destroy(&dev->ctxlist_mutex);
    mutex_destroy(&dev->clientlist_mutex);
    mutex_destroy(&dev->filelist_mutex);
    mutex_destroy(&dev->struct_mutex);
    return ret;
}

上一篇:【HTML5 API】类型化数组和ArrayBuffer


下一篇:本周学习内容---算法+js基础