[Intel-gfx] [RFC PATCH 1/3] drm/i915: Creating writeback pipeline to bypass drm_writeback framework

Kandpal, Suraj suraj.kandpal at intel.com
Thu Apr 28 05:52:16 UTC 2022


++Laurent ,Dmitry, and Abhinav

> Changes to create a i915 private pipeline to enable the WD transcoder
> without relying on the current drm_writeback framework.
> 
> Signed-off-by: Suraj Kandpal <suraj.kandpal at intel.com>
> ---
>  drivers/gpu/drm/i915/Makefile                 |   1 +
>  .../drm/i915/display/intel_display_types.h    |   4 +
>  .../gpu/drm/i915/display/intel_wb_connector.c | 296
> ++++++++++++++++++  .../gpu/drm/i915/display/intel_wb_connector.h |
> 99 ++++++
>  drivers/gpu/drm/i915/i915_drv.h               |   3 +
>  5 files changed, 403 insertions(+)
>  create mode 100644 drivers/gpu/drm/i915/display/intel_wb_connector.c
>  create mode 100644 drivers/gpu/drm/i915/display/intel_wb_connector.h
> 
> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
> index 1a771ee5b1d0..087bd9d1b397 100644
> --- a/drivers/gpu/drm/i915/Makefile
> +++ b/drivers/gpu/drm/i915/Makefile
> @@ -286,6 +286,7 @@ i915-y += \
>  	display/intel_tv.o \
>  	display/intel_vdsc.o \
>  	display/intel_vrr.o \
> +	display/intel_wb_connector.o\
>  	display/vlv_dsi.o \
>  	display/vlv_dsi_pll.o
> 
> diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h
> b/drivers/gpu/drm/i915/display/intel_display_types.h
> index d84e82f3eab9..7a96ecba73c0 100644
> --- a/drivers/gpu/drm/i915/display/intel_display_types.h
> +++ b/drivers/gpu/drm/i915/display/intel_display_types.h
> @@ -52,6 +52,7 @@
>  #include "intel_display_power.h"
>  #include "intel_dpll_mgr.h"
>  #include "intel_pm_types.h"
> +#include "intel_wb_connector.h"
> 
>  struct drm_printer;
>  struct __intel_global_objs_state;
> @@ -537,11 +538,14 @@ struct intel_connector {
>  	struct work_struct modeset_retry_work;
> 
>  	struct intel_hdcp hdcp;
> +
> +	struct intel_writeback_connector wb_conn;
>  };
> 
>  struct intel_digital_connector_state {
>  	struct drm_connector_state base;
> 
> +	struct intel_writeback_job *job;
>  	enum hdmi_force_audio force_audio;
>  	int broadcast_rgb;
>  };
> diff --git a/drivers/gpu/drm/i915/display/intel_wb_connector.c
> b/drivers/gpu/drm/i915/display/intel_wb_connector.c
> new file mode 100644
> index 000000000000..65f4abef53d0
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/display/intel_wb_connector.c
> @@ -0,0 +1,296 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright © 2022 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person
> +obtaining a
> + * copy of this software and associated documentation files (the
> +"Software"),
> + * to deal in the Software without restriction, including without
> +limitation
> + * the rights to use, copy, modify, merge, publish, distribute,
> +sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom
> +the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the
> +next
> + * paragraph) shall be included in all copies or substantial portions
> +of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> +EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> +MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO
> EVENT
> +SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
> DAMAGES OR
> +OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> +ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> OTHER
> +DEALINGS
> + * IN THE SOFTWARE.
> + *
> + * Authors:
> + *	Suraj Kandpal <suraj.kandpal at intel.com>
> + *	Arun Murthy <arun.r.murthy at intel.com>
> + *
> + */
> +
> +
> +#include <linux/dma-fence.h>
> +
> +#include <drm/drm_crtc.h>
> +#include <drm/drm_device.h>
> +#include <drm/drm_drv.h>
> +#include <drm/drm_modeset_helper_vtables.h>
> +#include <drm/drm_property.h>
> +
> +#include "i915_drv.h"
> +#include "intel_wb_connector.h"
> +#include "intel_display_types.h"
> +
> +#define fence_to_wb_connector(x) container_of(x->lock, \
> +					      struct intel_writeback_connector,
> \
> +					      fence_lock)
> +
> +static const char *intel_writeback_fence_get_driver_name(struct
> +dma_fence *fence) {
> +	struct intel_writeback_connector *wb_connector =
> +		fence_to_wb_connector(fence);
> +
> +	return wb_connector->base->dev->driver->name;
> +}
> +
> +static const char *
> +intel_writeback_fence_get_timeline_name(struct dma_fence *fence) {
> +	struct intel_writeback_connector *wb_connector =
> +		fence_to_wb_connector(fence);
> +
> +	return wb_connector->timeline_name;
> +}
> +
> +static bool intel_writeback_fence_enable_signaling(struct dma_fence
> +*fence) {
> +	return true;
> +}
> +
> +static const struct dma_fence_ops intel_writeback_fence_ops = {
> +	.get_driver_name = intel_writeback_fence_get_driver_name,
> +	.get_timeline_name = intel_writeback_fence_get_timeline_name,
> +	.enable_signaling = intel_writeback_fence_enable_signaling,
> +};
> +
> +static int intel_create_writeback_properties(struct drm_device *dev) {
> +	struct drm_property *prop;
> +	struct drm_i915_private *i915 = to_i915(dev);
> +
> +	if (!i915->wb_fb_id_property) {
> +		prop = drm_property_create_object(dev,
> DRM_MODE_PROP_ATOMIC,
> +						"WRITEBACK_FB_ID",
> +						DRM_MODE_OBJECT_FB);
> +		if (!prop)
> +			return -ENOMEM;
> +		i915->wb_fb_id_property = prop;
> +	}
> +
> +	if (!i915->wb_pixel_formats_property) {
> +		prop = drm_property_create(dev, DRM_MODE_PROP_BLOB
> |
> +					DRM_MODE_PROP_ATOMIC |
> +					DRM_MODE_PROP_IMMUTABLE,
> +					"WRITEBACK_PIXEL_FORMATS", 0);
> +		if (!prop)
> +			return -ENOMEM;
> +		i915->wb_pixel_formats_property = prop;
> +	}
> +
> +	if (!i915->wb_out_fence_ptr_property) {
> +		prop = drm_property_create_range(dev,
> DRM_MODE_PROP_ATOMIC,
> +
> 	"WRITEBACK_OUT_FENCE_PTR", 0,
> +						U64_MAX);
> +		if (!prop)
> +			return -ENOMEM;
> +		i915->wb_out_fence_ptr_property = prop;
> +	}
> +
> +	return 0;
> +}
> +
> +static const struct drm_encoder_funcs intel_writeback_encoder_funcs = {
> +	.destroy = drm_encoder_cleanup,
> +};
> +
> +int intel_writeback_connector_init(struct drm_device *dev,
> +				 struct intel_writeback_connector
> *wb_connector,
> +				 const struct drm_connector_funcs
> *con_funcs,
> +				 const struct drm_encoder_helper_funcs
> *enc_helper_funcs,
> +				 const u32 *formats, int n_formats) {
> +	struct drm_property_blob *blob;
> +	struct drm_i915_private *i915 = to_i915(dev);
> +	struct drm_connector *connector = wb_connector->base;
> +	int ret;
> +
> +	drm_dbg_kms(&i915->drm, "\n");
> +	ret = intel_create_writeback_properties(dev);
> +
> +	if (ret != 0)
> +		return ret;
> +
> +	blob = drm_property_create_blob(dev, n_formats *
> sizeof(*formats),
> +					formats);
> +	if (IS_ERR(blob))
> +		return PTR_ERR(blob);
> +
> +	drm_encoder_helper_add(wb_connector->encoder,
> enc_helper_funcs);
> +	ret = drm_encoder_init(dev, wb_connector->encoder,
> +			&intel_writeback_encoder_funcs,
> +			DRM_MODE_ENCODER_VIRTUAL, NULL);
> +	if (ret)
> +		goto fail;
> +
> +	connector->interlace_allowed = 0;
> +
> +	ret = drm_connector_init(dev, connector, con_funcs,
> +				DRM_MODE_CONNECTOR_WRITEBACK);
> +	if (ret)
> +		goto connector_fail;
> +
> +	ret = drm_connector_attach_encoder(connector,
> +					wb_connector->encoder);
> +	if (ret)
> +		goto attach_fail;
> +
> +	INIT_LIST_HEAD(&wb_connector->job_queue);
> +	spin_lock_init(&wb_connector->job_lock);
> +
> +	wb_connector->fence_context = dma_fence_context_alloc(1);
> +	spin_lock_init(&wb_connector->fence_lock);
> +	snprintf(wb_connector->timeline_name,
> +		sizeof(wb_connector->timeline_name),
> +		"CONNECTOR:%d-%s", connector->base.id, connector-
> >name);
> +
> +	drm_object_attach_property(&connector->base,
> +				i915->wb_out_fence_ptr_property, 0);
> +
> +	drm_object_attach_property(&connector->base,
> +				i915->wb_fb_id_property, 0);
> +
> +	drm_object_attach_property(&connector->base,
> +				i915->wb_pixel_formats_property,
> +				blob->base.id);
> +	wb_connector->pixel_formats_blob_ptr = blob;
> +
> +	return 0;
> +
> +attach_fail:
> +	drm_connector_cleanup(connector);
> +connector_fail:
> +	drm_encoder_cleanup(wb_connector->encoder);
> +fail:
> +	drm_property_blob_put(blob);
> +	return ret;
> +}
> +
> +void intel_writeback_queue_job(struct intel_writeback_connector
> *wb_connector,
> +		struct drm_connector_state *conn_state) {
> +	struct intel_writeback_job *wb_job;
> +	struct intel_digital_connector_state *intel_conn_state =
> +		to_intel_digital_connector_state(conn_state);
> +	unsigned long flags;
> +
> +	wb_job = intel_conn_state->job;
> +	intel_conn_state->job = NULL;
> +
> +	spin_lock_irqsave(&wb_connector->job_lock, flags);
> +	list_add_tail(&wb_job->list_entry, &wb_connector->job_queue);
> +	spin_unlock_irqrestore(&wb_connector->job_lock, flags); }
> +
> +int intel_writeback_set_fb(struct drm_connector_state *conn_state,
> +			 struct drm_framebuffer *fb)
> +{
> +	struct intel_connector *intel_connector =
> to_intel_connector(conn_state->connector);
> +	struct intel_writeback_connector *wb_connector =
> &intel_connector->wb_conn;
> +	struct intel_digital_connector_state *intel_conn_state =
> +		to_intel_digital_connector_state(conn_state);
> +	WARN_ON(conn_state->connector->connector_type !=
> +DRM_MODE_CONNECTOR_WRITEBACK);
> +
> +	if (!intel_conn_state->job) {
> +		intel_conn_state->job =
> +			kzalloc(sizeof(*intel_conn_state->job),
> GFP_KERNEL);
> +		if (!intel_conn_state->job)
> +			return -ENOMEM;
> +
> +		intel_conn_state->job->connector = wb_connector;
> +	}
> +
> +	drm_framebuffer_assign(&intel_conn_state->job->fb, fb);
> +	return 0;
> +}
> +
> +void intel_writeback_cleanup_job(struct intel_writeback_job *job) {
> +	if (job->fb)
> +		drm_framebuffer_put(job->fb);
> +
> +	if (job->out_fence)
> +		dma_fence_put(job->out_fence);
> +
> +	kfree(job);
> +}
> +
> +static void cleanup_work(struct work_struct *work) {
> +	struct intel_writeback_job *job = container_of(work,
> +						struct intel_writeback_job,
> +						cleanup_work);
> +
> +	intel_writeback_cleanup_job(job);
> +}
> +
> +void
> +intel_writeback_signal_completion(struct intel_writeback_connector
> *wb_connector,
> +				int status)
> +{
> +	unsigned long flags;
> +	struct intel_writeback_job *job;
> +	struct dma_fence *out_fence;
> +
> +	spin_lock_irqsave(&wb_connector->job_lock, flags);
> +	job = list_first_entry_or_null(&wb_connector->job_queue,
> +					struct intel_writeback_job,
> +					list_entry);
> +	if (job)
> +		list_del(&job->list_entry);
> +
> +	spin_unlock_irqrestore(&wb_connector->job_lock, flags);
> +
> +	if (WARN_ON(!job))
> +		return;
> +
> +	out_fence = job->out_fence;
> +	if (out_fence) {
> +		if (status)
> +			dma_fence_set_error(out_fence, status);
> +		dma_fence_signal(out_fence);
> +		dma_fence_put(out_fence);
> +		job->out_fence = NULL;
> +	}
> +
> +	INIT_WORK(&job->cleanup_work, cleanup_work);
> +	queue_work(system_long_wq, &job->cleanup_work); }
> +
> +struct dma_fence *
> +intel_writeback_get_out_fence(struct intel_writeback_connector
> +*wb_connector) {
> +	struct dma_fence *fence;
> +
> +	if (WARN_ON(wb_connector->base->connector_type !=
> +		DRM_MODE_CONNECTOR_WRITEBACK))
> +		return NULL;
> +
> +	fence = kzalloc(sizeof(*fence), GFP_KERNEL);
> +	if (!fence)
> +		return NULL;
> +
> +	dma_fence_init(fence, &intel_writeback_fence_ops,
> +		&wb_connector->fence_lock, wb_connector-
> >fence_context,
> +		++wb_connector->fence_seqno);
> +
> +	return fence;
> +}
> diff --git a/drivers/gpu/drm/i915/display/intel_wb_connector.h
> b/drivers/gpu/drm/i915/display/intel_wb_connector.h
> new file mode 100644
> index 000000000000..71142457b7c1
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/display/intel_wb_connector.h
> @@ -0,0 +1,99 @@
> +/* SPDX-License-Identifier: GPL-2.0
> + * Copyright © 2022 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person
> +obtaining a
> + * copy of this software and associated documentation files (the
> +"Software"),
> + * to deal in the Software without restriction, including without
> +limitation
> + * the rights to use, copy, modify, merge, publish, distribute,
> +sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom
> +the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the
> +next
> + * paragraph) shall be included in all copies or substantial portions
> +of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> +EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> +MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO
> EVENT
> +SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
> DAMAGES OR
> +OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> +ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> OTHER
> +DEALINGS
> + * IN THE SOFTWARE.
> + *
> + * Authors:
> + *	Suraj Kandpal <suraj.kandpal at intel.com>
> + *	Arun Murthy <arun.r.murthy at intel.com>
> + *
> + */
> +
> +#ifndef __INTEL_WB_CONNECTOR_H__
> +#define __INTEL_WB_CONNECTOR_H__
> +
> +#include <drm/drm_connector.h>
> +#include <drm/drm_encoder.h>
> +#include <linux/workqueue.h>
> +#include "intel_display.h"
> +
> +/**
> + * struct intel_writeback_connector - Intel writeback connector
> + * to get a idea of each individual variable please look at
> + * documentation in drm_writeback.h we emulate the same structure
> + * ditto for intel_writeback_job structure.
> + */
> +struct intel_writeback_connector {
> +	struct drm_connector *base;
> +	struct drm_encoder *encoder;
> +	struct drm_property_blob *pixel_formats_blob_ptr;
> +	spinlock_t job_lock;
> +	struct list_head job_queue;
> +	unsigned int fence_context;
> +	spinlock_t fence_lock;
> +	unsigned long fence_seqno;
> +	char timeline_name[32];
> +};
> +
> +/**
> + * struct intel_writeback_job - DRM writeback job  */ struct
> +intel_writeback_job {
> +	struct intel_writeback_connector *connector;
> +	bool *prepared;
> +	struct work_struct cleanup_work;
> +	struct list_head list_entry;
> +	struct drm_framebuffer *fb;
> +	struct dma_fence *out_fence;
> +	void *priv;
> +};
> +
> +int intel_writeback_connector_init(struct drm_device *dev,
> +			struct intel_writeback_connector *wb_connector,
> +			const struct drm_connector_funcs *con_funcs,
> +			const struct drm_encoder_helper_funcs
> *enc_helper_funcs,
> +			const u32 *formats, int n_formats);
> +
> +int intel_writeback_set_fb(struct drm_connector_state *conn_state,
> +			struct drm_framebuffer *fb);
> +
> +int intel_writeback_prepare_job(struct intel_writeback_job *job);
> +
> +void intel_writeback_queue_job(struct intel_writeback_connector
> *wb_connector,
> +			struct drm_connector_state *conn_state);
> +
> +void intel_writeback_cleanup_job(struct intel_writeback_job *job);
> +
> +void
> +intel_writeback_signal_completion(struct intel_writeback_connector
> *wb_connector,
> +			int status);
> +
> +struct dma_fence *
> +intel_writeback_get_out_fence(struct intel_writeback_connector
> +*wb_connector); struct intel_wb_connector
> +*intel_wb_connector_alloc(void); void intel_wb_connector_free(struct
> +intel_wb_connector *connector); void intel_wb_connector_destroy(struct
> +drm_connector *connector); bool
> intel_wb_connector_get_hw_state(struct
> +intel_wb_connector *connector); enum pipe
> +intel_wb_connector_get_pipe(struct intel_wb_connector *connector);
> void intel_wb_connector_attach_encoder(struct intel_wb_connector
> *connector,
> +					struct intel_encoder *encoder);
> +
> +#endif /* __INTEL_WB_CONNECTOR_H__ */
> +
> diff --git a/drivers/gpu/drm/i915/i915_drv.h
> b/drivers/gpu/drm/i915/i915_drv.h index 26df561a4e94..9a86ee88089e
> 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -678,6 +678,9 @@ struct drm_i915_private {
> 
>  	struct drm_property *broadcast_rgb_property;
>  	struct drm_property *force_audio_property;
> +	struct drm_property *wb_fb_id_property;
> +	struct drm_property *wb_out_fence_ptr_property;
> +	struct drm_property *wb_pixel_formats_property;
> 
>  	u32 fdi_rx_config;
> 
> --
> 2.35.1



More information about the Intel-gfx mailing list