目录
1.2 根据应用传入的fb_id,找到对应的drm_framebuffer
1.3 根据应用传入的mode,创建一个drm_display_mode
1.4 根据传入的set_connectors_ptr,找到驱动对应的connector
1.5 将以上信息转为struct drm_mode_set并调用__drm_mode_set_config_internal
1.6 __drm_mode_set_config_internal
2. drm_atomic_helper_set_config
本文分析一下drm_mode_setcrtc。
- int drm_mode_setcrtc(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
- {
- ......
-
- crtc = drm_crtc_find(dev, crtc_req->crtc_id);
- if (!crtc) {
- DRM_DEBUG_KMS("Unknown CRTC ID %d\n", crtc_req->crtc_id);
- return -ENOENT;
- }
- DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name);
- if (crtc_req->mode_valid) {
- /* If we have a mode we need a framebuffer. */
- /* If we pass -1, set the mode with the currently bound fb */
- if (crtc_req->fb_id == -1) {
- if (!crtc->primary->fb) {
- DRM_DEBUG_KMS("CRTC doesn't have current FB\n");
- ret = -EINVAL;
- goto out;
- }
- fb = crtc->primary->fb;
- /* Make refcounting symmetric with the lookup path. */
- drm_framebuffer_get(fb);
- } else {
- fb = drm_framebuffer_lookup(dev, crtc_req->fb_id);
- if (!fb) {
- DRM_DEBUG_KMS("Unknown FB ID%d\n",
- crtc_req->fb_id);
- ret = -ENOENT;
- goto out;
- }
- mode = drm_mode_create(dev);
- if (!mode) {
- ret = -ENOMEM;
- goto out;
- }
-
- ret = drm_mode_convert_umode(mode, &crtc_req->mode);
- if (ret) {
- DRM_DEBUG_KMS("Invalid mode\n");
- goto out;
- }
-
- /*
- * Check whether the primary plane supports the fb pixel format.
- * Drivers not implementing the universal planes API use a
- * default formats list provided by the DRM core which doesn't
- * match real hardware capabilities. Skip the check in that
- * case.
- */
- if (!crtc->primary->format_default) {
- ret = drm_plane_check_pixel_format(crtc->primary,
- fb->format->format);
- if (ret) {
- struct drm_format_name_buf format_name;
- DRM_DEBUG_KMS("Invalid pixel format %s\n",
- drm_get_format_name(fb->format->format,
- &format_name));
- goto out;
- }
- }
-
- ret = drm_crtc_check_viewport(crtc, crtc_req->x, crtc_req->y,
- mode, fb);
- if (ret)
- goto out;
- for (i = 0; i < crtc_req->count_connectors; i++) {
- connector_set[i] = NULL;
- set_connectors_ptr = (uint32_t __user *)(unsigned long)crtc_req->set_connectors_ptr;
- if (get_user(out_id, &set_connectors_ptr[i])) {
- ret = -EFAULT;
- goto out;
- }
-
- connector = drm_connector_lookup(dev, out_id);
- if (!connector) {
- DRM_DEBUG_KMS("Connector id %d unknown\n",
- out_id);
- ret = -ENOENT;
- goto out;
- }
- DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
- connector->base.id,
- connector->name);
-
- connector_set[i] = connector;
- }
- set.crtc = crtc;
- set.x = crtc_req->x;
- set.y = crtc_req->y;
- set.mode = mode;
- set.connectors = connector_set;
- set.num_connectors = crtc_req->count_connectors;
- set.fb = fb;
- ret = __drm_mode_set_config_internal(&set, &ctx);
-
- static int __drm_mode_set_config_internal(struct drm_mode_set *set,
- struct drm_modeset_acquire_ctx *ctx)
- {
- struct drm_crtc *crtc = set->crtc;
- struct drm_framebuffer *fb;
- struct drm_crtc *tmp;
- int ret;
-
- /*
- * NOTE: ->set_config can also disable other crtcs (if we steal all
- * connectors from it), hence we need to refcount the fbs across all
- * crtcs. Atomic modeset will have saner semantics ...
- */
- drm_for_each_crtc(tmp, crtc->dev)
- tmp->primary->old_fb = tmp->primary->fb;
-
- fb = set->fb;
-
- ret = crtc->funcs->set_config(set, ctx);
- if (ret == 0) {
- crtc->primary->crtc = crtc;
- crtc->primary->fb = fb;
- }
-
- drm_for_each_crtc(tmp, crtc->dev) {
- if (tmp->primary->fb)
- drm_framebuffer_get(tmp->primary->fb);
- if (tmp->primary->old_fb)
- drm_framebuffer_put(tmp->primary->old_fb);
- tmp->primary->old_fb = NULL;
- }
-
- return ret;
- }
只要是调用ret = crtc->funcs->set_config(set, ctx),即drm_atomic_helper_set_config,
- static const struct drm_crtc_funcs malidp_crtc_funcs = {
- .gamma_set = drm_atomic_helper_legacy_gamma_set,
- .destroy = drm_crtc_cleanup,
- .set_config = drm_atomic_helper_set_config,
- .page_flip = drm_atomic_helper_page_flip,
- .reset = malidp_crtc_reset,
- .atomic_duplicate_state = malidp_crtc_duplicate_state,
- .atomic_destroy_state = malidp_crtc_destroy_state,
- .enable_vblank = malidp_crtc_enable_vblank,
- .disable_vblank = malidp_crtc_disable_vblank,
- };
- int drm_atomic_helper_set_config(struct drm_mode_set *set,
- struct drm_modeset_acquire_ctx *ctx)
- {
- struct drm_atomic_state *state;
- struct drm_crtc *crtc = set->crtc;
- int ret = 0;
-
- state = drm_atomic_state_alloc(crtc->dev);
- if (!state)
- return -ENOMEM;
-
- state->acquire_ctx = ctx;
- ret = __drm_atomic_helper_set_config(set, state);
- if (ret != 0)
- goto fail;
-
- ret = handle_conflicting_encoders(state, true);
- if (ret)
- goto fail;
-
- ret = drm_atomic_commit(state);
-
- fail:
- drm_atomic_state_put(state);
- return ret;
- }
drm_atomic_helper_set_config主要涉及到结构体struct drm_atomic_state和drm_atomic_commit函数,我们后面会单独讨论这2个。