Пример #1
0
/**
 * 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;
}
Пример #2
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;
}
Пример #3
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;
}
Пример #4
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);
}
Пример #5
0
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);
}