++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@xxxxxxxxx> > --- > 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@xxxxxxxxx> > + * Arun Murthy <arun.r.murthy@xxxxxxxxx> > + * > + */ > + > + > +#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@xxxxxxxxx> > + * Arun Murthy <arun.r.murthy@xxxxxxxxx> > + * > + */ > + > +#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