/** * drm_atomic_crtc_set_property - set property on CRTC * @crtc: the drm CRTC to set a property on * @state: the state object to update with the new property value * @property: the property to set * @val: the new property value * * Use this instead of calling crtc->atomic_set_property directly. * This function handles generic/core properties and calls out to * driver's ->atomic_set_property() for driver properties. To ensure * consistent behavior you must call this function rather than the * driver hook directly. * * RETURNS: * Zero on success, error code on failure */ int drm_atomic_crtc_set_property(struct drm_crtc *crtc, struct drm_crtc_state *state, struct drm_property *property, uint64_t val) { struct drm_device *dev = crtc->dev; struct drm_mode_config *config = &dev->mode_config; int ret; if (property == config->prop_active) state->active = val; else if (property == config->prop_mode_id) { struct drm_property_blob *mode = drm_property_lookup_blob(dev, val); ret = drm_atomic_set_mode_prop_for_crtc(state, mode); if (mode) drm_property_unreference_blob(mode); return ret; } else if (crtc->funcs->atomic_set_property) return crtc->funcs->atomic_set_property(crtc, state, property, val); else return -EINVAL; return 0; }
/** * drm_atomic_set_mode_prop_for_crtc - set mode for CRTC * @state: the CRTC whose incoming state to update * @blob: pointer to blob property to use for mode * * Set a mode (originating from a blob property) on the desired CRTC state. * This function will take a reference on the blob property for the CRTC state, * and release the reference held on the state's existing mode property, if any * was set. * * RETURNS: * Zero on success, error code on failure. Cannot return -EDEADLK. */ int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state, struct drm_property_blob *blob) { if (blob == state->mode_blob) return 0; if (state->mode_blob) drm_property_unreference_blob(state->mode_blob); state->mode_blob = NULL; if (blob) { if (blob->length != sizeof(struct drm_mode_modeinfo) || drm_mode_convert_umode(&state->mode, (const struct drm_mode_modeinfo *) blob->data)) return -EINVAL; state->mode_blob = drm_property_reference_blob(blob); state->enable = true; DRM_DEBUG_ATOMIC("Set [MODE:%s] for CRTC state %p\n", state->mode.name, state); } else { memset(&state->mode, 0, sizeof(state->mode)); state->enable = false; DRM_DEBUG_ATOMIC("Set [NOMODE] for CRTC state %p\n", state); } return 0; }
/** * drm_atomic_set_mode_for_crtc - set mode for CRTC * @state: the CRTC whose incoming state to update * @mode: kernel-internal mode to use for the CRTC, or NULL to disable * * Set a mode (originating from the kernel) on the desired CRTC state. Does * not change any other state properties, including enable, active, or * mode_changed. * * RETURNS: * Zero on success, error code on failure. Cannot return -EDEADLK. */ int drm_atomic_set_mode_for_crtc(struct drm_crtc_state *state, struct drm_display_mode *mode) { struct drm_mode_modeinfo umode; /* Early return for no change. */ if (mode && memcmp(&state->mode, mode, sizeof(*mode)) == 0) return 0; if (state->mode_blob) drm_property_unreference_blob(state->mode_blob); state->mode_blob = NULL; if (mode) { drm_mode_convert_to_umode(&umode, mode); state->mode_blob = drm_property_create_blob(state->crtc->dev, sizeof(umode), &umode); if (IS_ERR(state->mode_blob)) return PTR_ERR(state->mode_blob); drm_mode_copy(&state->mode, mode); state->enable = true; DRM_DEBUG_ATOMIC("Set [MODE:%s] for CRTC state %p\n", mode->name, state); } else { memset(&state->mode, 0, sizeof(state->mode)); state->enable = false; DRM_DEBUG_ATOMIC("Set [NOMODE] for CRTC state %p\n", state); } return 0; }
static void sde_connector_destroy(struct drm_connector *connector) { struct sde_connector *c_conn; if (!connector) { SDE_ERROR("invalid connector\n"); return; } c_conn = to_sde_connector(connector); if (c_conn->ops.pre_deinit) c_conn->ops.pre_deinit(connector, c_conn->display); if (c_conn->blob_caps) drm_property_unreference_blob(c_conn->blob_caps); msm_property_destroy(&c_conn->property_info); drm_connector_unregister(connector); sde_fence_deinit(&c_conn->retire_fence); drm_connector_cleanup(connector); kfree(c_conn); }
struct drm_connector *sde_connector_init(struct drm_device *dev, struct drm_encoder *encoder, struct drm_panel *panel, void *display, const struct sde_connector_ops *ops, int connector_poll, int connector_type) { struct msm_drm_private *priv; struct sde_kms *sde_kms; struct sde_kms_info *info; struct sde_connector *c_conn = NULL; int rc; if (!dev || !dev->dev_private || !encoder) { SDE_ERROR("invalid argument(s), dev %pK, enc %pK\n", dev, encoder); return ERR_PTR(-EINVAL); } priv = dev->dev_private; if (!priv->kms) { SDE_ERROR("invalid kms reference\n"); return ERR_PTR(-EINVAL); } c_conn = kzalloc(sizeof(*c_conn), GFP_KERNEL); if (!c_conn) { SDE_ERROR("failed to alloc sde connector\n"); return ERR_PTR(-ENOMEM); } rc = drm_connector_init(dev, &c_conn->base, &sde_connector_ops, connector_type); if (rc) goto error_free_conn; c_conn->connector_type = connector_type; c_conn->encoder = encoder; c_conn->panel = panel; c_conn->display = display; /* cache mmu_id's for later */ sde_kms = to_sde_kms(priv->kms); if (sde_kms->vbif[VBIF_NRT]) { c_conn->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE] = sde_kms->mmu_id[MSM_SMMU_DOMAIN_NRT_UNSECURE]; c_conn->mmu_id[SDE_IOMMU_DOMAIN_SECURE] = sde_kms->mmu_id[MSM_SMMU_DOMAIN_NRT_SECURE]; } else { c_conn->mmu_id[SDE_IOMMU_DOMAIN_UNSECURE] = sde_kms->mmu_id[MSM_SMMU_DOMAIN_UNSECURE]; c_conn->mmu_id[SDE_IOMMU_DOMAIN_SECURE] = sde_kms->mmu_id[MSM_SMMU_DOMAIN_SECURE]; } if (ops) c_conn->ops = *ops; c_conn->base.helper_private = &sde_connector_helper_ops; c_conn->base.polled = connector_poll; c_conn->base.interlace_allowed = 0; c_conn->base.doublescan_allowed = 0; snprintf(c_conn->name, SDE_CONNECTOR_NAME_SIZE, "conn%u", c_conn->base.base.id); /* * Initialize retire fence support. Set fence offset to 0 for virtual * connectors so that the fence signals at the end of the current commit * and 1 for others so that the fence signals after one additional * commit. */ rc = sde_fence_init(dev, &c_conn->retire_fence, c_conn->name, connector_type == DRM_MODE_CONNECTOR_VIRTUAL ? 0 : 1); if (rc) { SDE_ERROR("failed to init fence, %d\n", rc); goto error_cleanup_conn; } rc = drm_connector_register(&c_conn->base); if (rc) { SDE_ERROR("failed to register drm connector, %d\n", rc); goto error_cleanup_fence; } rc = drm_mode_connector_attach_encoder(&c_conn->base, encoder); if (rc) { SDE_ERROR("failed to attach encoder to connector, %d\n", rc); goto error_unregister_conn; } /* create properties */ msm_property_init(&c_conn->property_info, &c_conn->base.base, dev, priv->conn_property, c_conn->property_data, CONNECTOR_PROP_COUNT, CONNECTOR_PROP_BLOBCOUNT, sizeof(struct sde_connector_state)); if (c_conn->ops.post_init) { info = kmalloc(sizeof(*info), GFP_KERNEL); if (!info) { SDE_ERROR("failed to allocate info buffer\n"); rc = -ENOMEM; goto error_unregister_conn; } sde_kms_info_reset(info); rc = c_conn->ops.post_init(&c_conn->base, info, display); if (rc) { SDE_ERROR("post-init failed, %d\n", rc); kfree(info); goto error_unregister_conn; } msm_property_install_blob(&c_conn->property_info, "capabilities", DRM_MODE_PROP_IMMUTABLE, CONNECTOR_PROP_SDE_INFO); msm_property_set_blob(&c_conn->property_info, &c_conn->blob_caps, SDE_KMS_INFO_DATA(info), SDE_KMS_INFO_DATALEN(info), CONNECTOR_PROP_SDE_INFO); kfree(info); } msm_property_install_range(&c_conn->property_info, "RETIRE_FENCE", 0x0, 0, INR_OPEN_MAX, 0, CONNECTOR_PROP_RETIRE_FENCE); /* enum/bitmask properties */ msm_property_install_enum(&c_conn->property_info, "topology_name", DRM_MODE_PROP_IMMUTABLE, 0, e_topology_name, ARRAY_SIZE(e_topology_name), CONNECTOR_PROP_TOPOLOGY_NAME, 0); msm_property_install_enum(&c_conn->property_info, "topology_control", 0, 1, e_topology_control, ARRAY_SIZE(e_topology_control), CONNECTOR_PROP_TOPOLOGY_CONTROL, 0); rc = msm_property_install_get_status(&c_conn->property_info); if (rc) { SDE_ERROR("failed to create one or more properties\n"); goto error_destroy_property; } SDE_DEBUG("connector %d attach encoder %d\n", c_conn->base.base.id, encoder->base.id); priv->connectors[priv->num_connectors++] = &c_conn->base; return &c_conn->base; error_destroy_property: if (c_conn->blob_caps) drm_property_unreference_blob(c_conn->blob_caps); msm_property_destroy(&c_conn->property_info); error_unregister_conn: drm_connector_unregister(&c_conn->base); error_cleanup_fence: sde_fence_deinit(&c_conn->retire_fence); error_cleanup_conn: drm_connector_cleanup(&c_conn->base); error_free_conn: kfree(c_conn); return ERR_PTR(rc); }