Message ID | 20220318041850.1398135-1-suraj.kandpal@intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | [RFC,v2,1/3] drm/i915: Creating writeback pipeline to bypass drm_writeback framework | expand |
++Uma Regards, Suraj Kandpal > 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@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@intel.com> > + * Arun Murthy <arun.r.murthy@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@intel.com> > + * Arun Murthy <arun.r.murthy@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
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@intel.com> + * Arun Murthy <arun.r.murthy@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@intel.com> + * Arun Murthy <arun.r.murthy@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;
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@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