All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v5 00/19] Add writeback block support for DPU
@ 2022-04-25  0:31 Abhinav Kumar
  2022-04-25  0:31 ` [PATCH v5 01/19] drm: allow passing possible_crtcs to drm_writeback_connector_init() Abhinav Kumar
                   ` (18 more replies)
  0 siblings, 19 replies; 29+ messages in thread
From: Abhinav Kumar @ 2022-04-25  0:31 UTC (permalink / raw)
  To: freedreno
  Cc: markyacoub, liviu.dudau, Abhinav Kumar, dri-devel, swboyd,
	seanpaul, laurent.pinchart, dmitry.baryshkov, quic_jesszhan,
	quic_aravindh

This series adds support for writeback block on DPU. Writeback
block is extremely useful to validate boards having no physical displays
in addition to many other use-cases where we want to get the output
of the display pipeline to examine whether issue is with the display
pipeline or with the panel.

These changes have been validated on SM8250 RB5 boards with IGT KMS
writeback test-suite thereby further increasing the IGT test coverage
for DPU. I am sharing the test results below.

root@linaro-developer:~/igt_repo/igt-gpu-tools/build/tests# ./kms_writeback
[   35.066157] Console: switching to colour dummy device 80x25
[   35.071964] [IGT] kms_writeback: executing
IGT-Version: 1.26-gae2eb9e1 (aarch64) (Linux: 5.16.0-rc2-62171-g132577e2697b aarch64)
[   35.611418] [IGT] kms_writeback: starting subtest writeback-pixel-formats
Starting subtest: writeback-pixel-formats
[   35.618528] [IGT] kms_writeback: starting subtest writeback-invalid-parameters
Subtest writeback-pixel-formats: SUCCESS (0.000s)
Starting subtest: writeback-invalid-parameters
Subtest writeback-invalid-parameters: SUCCESS (0.028s)   35.657437] [IGT] kms_writeback: starting subtest writeback-fb-id
Starting subtest: writeback-fb-id
Subtest writeback-fb-id: SUCCESS (0.030s)
[   35.698957] [IGT] kms_writeback: starting subtest writeback-check-output
Starting subtest: writeback-check-output
[   35.852834] [IGT] kms_writeback: exiting, ret=0
Subtest writeback-check-output: SUCCESS (0.142s)
[   35.861291] Console: switching to colour frame buffer device 240x67
root@linaro-developer:~/igt_repo/igt-gpu-tools/build/tests# 

The changes can easily be extended to support any other chipset using
the DPU driver by adding the support in the catalog.

Writeback block supports various formats and features. The support
for all of them can be incrementally added on top of this framework when
validation is improved and the test frameworks are extended to validate
them.

changes in v5:
	- fix drm_writeback_connector_init_with_encoder() API doc as
	  suggested by Laurent	
	- fix encoder doc as suggested by Laurent
	- drop https://patchwork.freedesktop.org/patch/483118/?series=99724&rev=4
	  and let individual drivers manage the encoder	

Abhinav Kumar (19):
  drm: allow passing possible_crtcs to drm_writeback_connector_init()
  drm: introduce drm_writeback_connector_init_with_encoder() API
  drm/msm/dpu: add writeback blocks to the sm8250 DPU catalog
  drm/msm/dpu: add reset_intf_cfg operation for dpu_hw_ctl
  drm/msm/dpu: rename dpu_hw_pipe_cdp_cfg to dpu_hw_cdp_cfg
  drm/msm/dpu: add dpu_hw_wb abstraction for writeback blocks
  drm/msm/dpu: add writeback blocks to DPU RM
  drm/msm/dpu: add changes to support writeback in hw_ctl
  drm/msm/dpu: add an API to reset the encoder related hw blocks
  drm/msm/dpu: make changes to dpu_encoder to support virtual encoder
  drm/msm/dpu: add encoder operations to prepare/cleanup wb job
  drm/msm/dpu: move _dpu_plane_get_qos_lut to dpu_hw_util file
  drm/msm/dpu: introduce the dpu_encoder_phys_* for writeback
  drm/msm/dpu: add the writeback connector layer
  drm/msm/dpu: initialize dpu encoder and connector for writeback
  drm/msm/dpu: gracefully handle null fb commits for writeback
  drm/msm/dpu: add writeback blocks to the display snapshot
  drm/msm/dpu: add wb_idx to existing DRM prints in dpu_encoder
  drm/msm/dpu: add wb_idx to DRM traces in dpu_encoder

 .../drm/arm/display/komeda/komeda_wb_connector.c   |   4 +-
 drivers/gpu/drm/arm/malidp_mw.c                    |   4 +-
 drivers/gpu/drm/drm_writeback.c                    |  73 +-
 drivers/gpu/drm/msm/Makefile                       |   3 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c           |   9 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c        | 306 +++++++--
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h        |  22 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h   |  50 ++
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c    | 763 +++++++++++++++++++++
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c     |  72 ++
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h     |  66 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c         |  82 ++-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h         |  21 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c        |   2 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h        |  18 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c        |  25 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h        |  19 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.c          | 279 ++++++++
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.h          | 115 ++++
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c            |  66 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c          |  31 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c             |  22 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h             |  12 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h          |  26 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c      |  76 ++
 drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.h      |  31 +
 drivers/gpu/drm/rcar-du/rcar_du_writeback.c        |   4 +-
 drivers/gpu/drm/vc4/vc4_txp.c                      |   3 +-
 drivers/gpu/drm/vkms/vkms_writeback.c              |   4 +-
 include/drm/drm_writeback.h                        |  11 +-
 30 files changed, 2091 insertions(+), 128 deletions(-)
 create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
 create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.c
 create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.h
 create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c
 create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.h

-- 
2.7.4


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH v5 01/19] drm: allow passing possible_crtcs to drm_writeback_connector_init()
  2022-04-25  0:31 [PATCH v5 00/19] Add writeback block support for DPU Abhinav Kumar
@ 2022-04-25  0:31 ` Abhinav Kumar
  2022-04-25  0:31 ` [PATCH v5 02/19] drm: introduce drm_writeback_connector_init_with_encoder() API Abhinav Kumar
                   ` (17 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: Abhinav Kumar @ 2022-04-25  0:31 UTC (permalink / raw)
  To: freedreno
  Cc: markyacoub, liviu.dudau, Abhinav Kumar, dri-devel, swboyd,
	seanpaul, laurent.pinchart, dmitry.baryshkov, quic_jesszhan,
	quic_aravindh

Clients of drm_writeback_connector_init() initialize the
possible_crtcs and then invoke the call to this API.

To simplify things, allow passing possible_crtcs as a parameter
to drm_writeback_connector_init() and make changes to the
other drm drivers to make them compatible with this change.

changes in v2:
	- split the changes according to their functionality

changes in v3:
	- allow passing possible_crtcs for existing users of
	  drm_writeback_connector_init()
	- squash the vendor changes into the same commit so
	  that each patch in the series can compile individually

changes in v4:
    - keep only changes related to possible_crtcs
	- add line breaks after ARRAY_SIZE
	- stop using temporary variables for possible_crtcs

changes in v5:
    - None

changes in v6:
    - None

changes in v7:
	- wrap long lines to match the coding style of existing drivers
	- Fix indentation and remove parenthesis where not needed
	- use u32 instead of uint32_t for possible_crtcs

Signed-off-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
Acked-by: Liviu Dudau <liviu.dudau@arm.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/gpu/drm/arm/display/komeda/komeda_wb_connector.c | 4 ++--
 drivers/gpu/drm/arm/malidp_mw.c                          | 4 ++--
 drivers/gpu/drm/drm_writeback.c                          | 7 ++++++-
 drivers/gpu/drm/rcar-du/rcar_du_writeback.c              | 4 ++--
 drivers/gpu/drm/vc4/vc4_txp.c                            | 3 ++-
 drivers/gpu/drm/vkms/vkms_writeback.c                    | 4 ++--
 include/drm/drm_writeback.h                              | 3 ++-
 7 files changed, 18 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_wb_connector.c b/drivers/gpu/drm/arm/display/komeda/komeda_wb_connector.c
index e465cc4..ce4b760 100644
--- a/drivers/gpu/drm/arm/display/komeda/komeda_wb_connector.c
+++ b/drivers/gpu/drm/arm/display/komeda/komeda_wb_connector.c
@@ -155,7 +155,6 @@ static int komeda_wb_connector_add(struct komeda_kms_dev *kms,
 	kwb_conn->wb_layer = kcrtc->master->wb_layer;
 
 	wb_conn = &kwb_conn->base;
-	wb_conn->encoder.possible_crtcs = BIT(drm_crtc_index(&kcrtc->base));
 
 	formats = komeda_get_layer_fourcc_list(&mdev->fmt_tbl,
 					       kwb_conn->wb_layer->layer_type,
@@ -164,7 +163,8 @@ static int komeda_wb_connector_add(struct komeda_kms_dev *kms,
 	err = drm_writeback_connector_init(&kms->base, wb_conn,
 					   &komeda_wb_connector_funcs,
 					   &komeda_wb_encoder_helper_funcs,
-					   formats, n_formats);
+					   formats, n_formats,
+					   BIT(drm_crtc_index(&kcrtc->base)));
 	komeda_put_fourcc_list(formats);
 	if (err) {
 		kfree(kwb_conn);
diff --git a/drivers/gpu/drm/arm/malidp_mw.c b/drivers/gpu/drm/arm/malidp_mw.c
index f5847a7..204c869 100644
--- a/drivers/gpu/drm/arm/malidp_mw.c
+++ b/drivers/gpu/drm/arm/malidp_mw.c
@@ -212,7 +212,6 @@ int malidp_mw_connector_init(struct drm_device *drm)
 	if (!malidp->dev->hw->enable_memwrite)
 		return 0;
 
-	malidp->mw_connector.encoder.possible_crtcs = 1 << drm_crtc_index(&malidp->crtc);
 	drm_connector_helper_add(&malidp->mw_connector.base,
 				 &malidp_mw_connector_helper_funcs);
 
@@ -223,7 +222,8 @@ int malidp_mw_connector_init(struct drm_device *drm)
 	ret = drm_writeback_connector_init(drm, &malidp->mw_connector,
 					   &malidp_mw_connector_funcs,
 					   &malidp_mw_encoder_helper_funcs,
-					   formats, n_formats);
+					   formats, n_formats,
+					   1 << drm_crtc_index(&malidp->crtc));
 	kfree(formats);
 	if (ret)
 		return ret;
diff --git a/drivers/gpu/drm/drm_writeback.c b/drivers/gpu/drm/drm_writeback.c
index dccf4504..9e0b845 100644
--- a/drivers/gpu/drm/drm_writeback.c
+++ b/drivers/gpu/drm/drm_writeback.c
@@ -157,6 +157,7 @@ static const struct drm_encoder_funcs drm_writeback_encoder_funcs = {
  * @enc_helper_funcs: Encoder helper funcs vtable to be used by the internal encoder
  * @formats: Array of supported pixel formats for the writeback engine
  * @n_formats: Length of the formats array
+ * @possible_crtcs: possible crtcs for the internal writeback encoder
  *
  * This function creates the writeback-connector-specific properties if they
  * have not been already created, initializes the connector as
@@ -174,7 +175,8 @@ int drm_writeback_connector_init(struct drm_device *dev,
 				 struct drm_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)
+				 const u32 *formats, int n_formats,
+				 u32 possible_crtcs)
 {
 	struct drm_property_blob *blob;
 	struct drm_connector *connector = &wb_connector->base;
@@ -190,6 +192,9 @@ int drm_writeback_connector_init(struct drm_device *dev,
 		return PTR_ERR(blob);
 
 	drm_encoder_helper_add(&wb_connector->encoder, enc_helper_funcs);
+
+	wb_connector->encoder.possible_crtcs = possible_crtcs;
+
 	ret = drm_encoder_init(dev, &wb_connector->encoder,
 			       &drm_writeback_encoder_funcs,
 			       DRM_MODE_ENCODER_VIRTUAL, NULL);
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_writeback.c b/drivers/gpu/drm/rcar-du/rcar_du_writeback.c
index c79d125..505a905 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_writeback.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_writeback.c
@@ -200,7 +200,6 @@ int rcar_du_writeback_init(struct rcar_du_device *rcdu,
 {
 	struct drm_writeback_connector *wb_conn = &rcrtc->writeback;
 
-	wb_conn->encoder.possible_crtcs = 1 << drm_crtc_index(&rcrtc->crtc);
 	drm_connector_helper_add(&wb_conn->base,
 				 &rcar_du_wb_conn_helper_funcs);
 
@@ -208,7 +207,8 @@ int rcar_du_writeback_init(struct rcar_du_device *rcdu,
 					    &rcar_du_wb_conn_funcs,
 					    &rcar_du_wb_enc_helper_funcs,
 					    writeback_formats,
-					    ARRAY_SIZE(writeback_formats));
+					    ARRAY_SIZE(writeback_formats),
+					    1 << drm_crtc_index(&rcrtc->crtc));
 }
 
 void rcar_du_writeback_setup(struct rcar_du_crtc *rcrtc,
diff --git a/drivers/gpu/drm/vc4/vc4_txp.c b/drivers/gpu/drm/vc4/vc4_txp.c
index 9809ca3..3447eb6 100644
--- a/drivers/gpu/drm/vc4/vc4_txp.c
+++ b/drivers/gpu/drm/vc4/vc4_txp.c
@@ -497,7 +497,8 @@ static int vc4_txp_bind(struct device *dev, struct device *master, void *data)
 	ret = drm_writeback_connector_init(drm, &txp->connector,
 					   &vc4_txp_connector_funcs,
 					   &vc4_txp_encoder_helper_funcs,
-					   drm_fmts, ARRAY_SIZE(drm_fmts));
+					   drm_fmts, ARRAY_SIZE(drm_fmts),
+					   0);
 	if (ret)
 		return ret;
 
diff --git a/drivers/gpu/drm/vkms/vkms_writeback.c b/drivers/gpu/drm/vkms/vkms_writeback.c
index af1604d..0a31522 100644
--- a/drivers/gpu/drm/vkms/vkms_writeback.c
+++ b/drivers/gpu/drm/vkms/vkms_writeback.c
@@ -140,12 +140,12 @@ int vkms_enable_writeback_connector(struct vkms_device *vkmsdev)
 {
 	struct drm_writeback_connector *wb = &vkmsdev->output.wb_connector;
 
-	vkmsdev->output.wb_connector.encoder.possible_crtcs = 1;
 	drm_connector_helper_add(&wb->base, &vkms_wb_conn_helper_funcs);
 
 	return drm_writeback_connector_init(&vkmsdev->drm, wb,
 					    &vkms_wb_connector_funcs,
 					    &vkms_wb_encoder_helper_funcs,
 					    vkms_wb_formats,
-					    ARRAY_SIZE(vkms_wb_formats));
+					    ARRAY_SIZE(vkms_wb_formats),
+					    1);
 }
diff --git a/include/drm/drm_writeback.h b/include/drm/drm_writeback.h
index 9697d27..5d9263f 100644
--- a/include/drm/drm_writeback.h
+++ b/include/drm/drm_writeback.h
@@ -150,7 +150,8 @@ int drm_writeback_connector_init(struct drm_device *dev,
 				 struct drm_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);
+				 const u32 *formats, int n_formats,
+				 u32 possible_crtcs);
 
 int drm_writeback_set_fb(struct drm_connector_state *conn_state,
 			 struct drm_framebuffer *fb);
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v5 02/19] drm: introduce drm_writeback_connector_init_with_encoder() API
  2022-04-25  0:31 [PATCH v5 00/19] Add writeback block support for DPU Abhinav Kumar
  2022-04-25  0:31 ` [PATCH v5 01/19] drm: allow passing possible_crtcs to drm_writeback_connector_init() Abhinav Kumar
@ 2022-04-25  0:31 ` Abhinav Kumar
  2022-04-25  0:31 ` [PATCH v5 03/19] drm/msm/dpu: add writeback blocks to the sm8250 DPU catalog Abhinav Kumar
                   ` (16 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: Abhinav Kumar @ 2022-04-25  0:31 UTC (permalink / raw)
  To: freedreno
  Cc: markyacoub, liviu.dudau, Abhinav Kumar, dri-devel, swboyd,
	seanpaul, laurent.pinchart, dmitry.baryshkov, quic_jesszhan,
	quic_aravindh

For vendors drivers which pass an already allocated and
initialized encoder especially for cases where the encoder
hardware is shared OR the writeback encoder shares the resources
with the rest of the display pipeline introduce a new API,
drm_writeback_connector_init_with_encoder() which expects
an initialized encoder as a parameter and only sets up the
writeback connector.

changes in v5:
	- fix the encoder doc to indicate that its not valid for
	  users of drm_writeback_connector_init_with_encoder()

Reviewed-by: Liviu Dudau <liviu.dudau@arm.com>
Signed-off-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/gpu/drm/drm_writeback.c | 72 +++++++++++++++++++++++++++++++++--------
 include/drm/drm_writeback.h     |  8 +++++
 2 files changed, 66 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/drm_writeback.c b/drivers/gpu/drm/drm_writeback.c
index 9e0b845..99fd15d 100644
--- a/drivers/gpu/drm/drm_writeback.c
+++ b/drivers/gpu/drm/drm_writeback.c
@@ -178,6 +178,62 @@ int drm_writeback_connector_init(struct drm_device *dev,
 				 const u32 *formats, int n_formats,
 				 u32 possible_crtcs)
 {
+	int ret = 0;
+
+	drm_encoder_helper_add(&wb_connector->encoder, enc_helper_funcs);
+
+	wb_connector->encoder.possible_crtcs = possible_crtcs;
+
+	ret = drm_encoder_init(dev, &wb_connector->encoder,
+			       &drm_writeback_encoder_funcs,
+			       DRM_MODE_ENCODER_VIRTUAL, NULL);
+	if (ret)
+		return ret;
+
+	ret = drm_writeback_connector_init_with_encoder(dev, wb_connector, &wb_connector->encoder,
+			con_funcs, formats, n_formats);
+
+	if (ret)
+		drm_encoder_cleanup(&wb_connector->encoder);
+
+	return ret;
+}
+EXPORT_SYMBOL(drm_writeback_connector_init);
+
+/**
+ * drm_writeback_connector_init_with_encoder - Initialize a writeback connector with
+ * a custom encoder
+ *
+ * @dev: DRM device
+ * @wb_connector: Writeback connector to initialize
+ * @enc: handle to the already initialized drm encoder
+ * @con_funcs: Connector funcs vtable
+ * @formats: Array of supported pixel formats for the writeback engine
+ * @n_formats: Length of the formats array
+ *
+ * This function creates the writeback-connector-specific properties if they
+ * have not been already created, initializes the connector as
+ * type DRM_MODE_CONNECTOR_WRITEBACK, and correctly initializes the property
+ * values.
+ *
+ * This function assumes that the drm_writeback_connector's encoder has already been
+ * created and initialized before invoking this function.
+ *
+ * In addition, this function also assumes that callers of this API will manage
+ * assigning the encoder helper functions, possible_crtcs and any other encoder
+ * specific operation.
+ *
+ * Drivers should always use this function instead of drm_connector_init() to
+ * set up writeback connectors if they want to manage themselves the lifetime of the
+ * associated encoder.
+ *
+ * Returns: 0 on success, or a negative error code
+ */
+int drm_writeback_connector_init_with_encoder(struct drm_device *dev,
+		struct drm_writeback_connector *wb_connector, struct drm_encoder *enc,
+		const struct drm_connector_funcs *con_funcs, const u32 *formats,
+		int n_formats)
+{
 	struct drm_property_blob *blob;
 	struct drm_connector *connector = &wb_connector->base;
 	struct drm_mode_config *config = &dev->mode_config;
@@ -191,15 +247,6 @@ int drm_writeback_connector_init(struct drm_device *dev,
 	if (IS_ERR(blob))
 		return PTR_ERR(blob);
 
-	drm_encoder_helper_add(&wb_connector->encoder, enc_helper_funcs);
-
-	wb_connector->encoder.possible_crtcs = possible_crtcs;
-
-	ret = drm_encoder_init(dev, &wb_connector->encoder,
-			       &drm_writeback_encoder_funcs,
-			       DRM_MODE_ENCODER_VIRTUAL, NULL);
-	if (ret)
-		goto fail;
 
 	connector->interlace_allowed = 0;
 
@@ -208,8 +255,7 @@ int drm_writeback_connector_init(struct drm_device *dev,
 	if (ret)
 		goto connector_fail;
 
-	ret = drm_connector_attach_encoder(connector,
-						&wb_connector->encoder);
+	ret = drm_connector_attach_encoder(connector, enc);
 	if (ret)
 		goto attach_fail;
 
@@ -238,12 +284,10 @@ int drm_writeback_connector_init(struct drm_device *dev,
 attach_fail:
 	drm_connector_cleanup(connector);
 connector_fail:
-	drm_encoder_cleanup(&wb_connector->encoder);
-fail:
 	drm_property_blob_put(blob);
 	return ret;
 }
-EXPORT_SYMBOL(drm_writeback_connector_init);
+EXPORT_SYMBOL(drm_writeback_connector_init_with_encoder);
 
 int drm_writeback_set_fb(struct drm_connector_state *conn_state,
 			 struct drm_framebuffer *fb)
diff --git a/include/drm/drm_writeback.h b/include/drm/drm_writeback.h
index 5d9263f..17e576c 100644
--- a/include/drm/drm_writeback.h
+++ b/include/drm/drm_writeback.h
@@ -30,6 +30,8 @@ struct drm_writeback_connector {
 	 * @drm_writeback_connector control the behaviour of the @encoder
 	 * by passing the @enc_funcs parameter to drm_writeback_connector_init()
 	 * function.
+	 * For users of drm_writeback_connector_init_with_encoder(), this field
+	 * is not valid as the encoder is managed within their drivers.
 	 */
 	struct drm_encoder encoder;
 
@@ -153,6 +155,12 @@ int drm_writeback_connector_init(struct drm_device *dev,
 				 const u32 *formats, int n_formats,
 				 u32 possible_crtcs);
 
+int drm_writeback_connector_init_with_encoder(struct drm_device *dev,
+				struct drm_writeback_connector *wb_connector,
+				struct drm_encoder *enc,
+				const struct drm_connector_funcs *con_funcs, const u32 *formats,
+				int n_formats);
+
 int drm_writeback_set_fb(struct drm_connector_state *conn_state,
 			 struct drm_framebuffer *fb);
 
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v5 03/19] drm/msm/dpu: add writeback blocks to the sm8250 DPU catalog
  2022-04-25  0:31 [PATCH v5 00/19] Add writeback block support for DPU Abhinav Kumar
  2022-04-25  0:31 ` [PATCH v5 01/19] drm: allow passing possible_crtcs to drm_writeback_connector_init() Abhinav Kumar
  2022-04-25  0:31 ` [PATCH v5 02/19] drm: introduce drm_writeback_connector_init_with_encoder() API Abhinav Kumar
@ 2022-04-25  0:31 ` Abhinav Kumar
  2022-04-25  0:31 ` [PATCH v5 04/19] drm/msm/dpu: add reset_intf_cfg operation for dpu_hw_ctl Abhinav Kumar
                   ` (15 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: Abhinav Kumar @ 2022-04-25  0:31 UTC (permalink / raw)
  To: freedreno
  Cc: markyacoub, liviu.dudau, Abhinav Kumar, dri-devel, swboyd,
	seanpaul, laurent.pinchart, dmitry.baryshkov, quic_jesszhan,
	quic_aravindh

Add writeback blocks to the sm8250 DPU hardware catalog. Other
chipsets support writeback too but add it to sm8250 to prototype
the feature so that it can be easily extended to other chipsets.

changes in v4:
	- fix the copyright year order

Signed-off-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c | 72 ++++++++++++++++++++++++++
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 66 ++++++++++++++++++++++-
 2 files changed, 137 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
index b0a0ef7..7e3f0f4 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022. Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #define pr_fmt(fmt)	"[drm:%s:%d] " fmt, __func__, __LINE__
@@ -120,6 +121,16 @@
 			  BIT(MDP_AD4_0_INTR) | \
 			  BIT(MDP_AD4_1_INTR))
 
+#define WB_SM8250_MASK (BIT(DPU_WB_LINE_MODE) | \
+			 BIT(DPU_WB_UBWC) | \
+			 BIT(DPU_WB_YUV_CONFIG) | \
+			 BIT(DPU_WB_PIPE_ALPHA) | \
+			 BIT(DPU_WB_XY_ROI_OFFSET) | \
+			 BIT(DPU_WB_QOS) | \
+			 BIT(DPU_WB_QOS_8LVL) | \
+			 BIT(DPU_WB_CDP) | \
+			 BIT(DPU_WB_INPUT_CTRL))
+
 #define DEFAULT_PIXEL_RAM_SIZE		(50 * 1024)
 #define DEFAULT_DPU_LINE_WIDTH		2048
 #define DEFAULT_DPU_OUTPUT_LINE_WIDTH	2560
@@ -211,6 +222,40 @@ static const u32 rotation_v2_formats[] = {
 	/* TODO add formats after validation */
 };
 
+static const uint32_t wb2_formats[] = {
+	DRM_FORMAT_RGB565,
+	DRM_FORMAT_BGR565,
+	DRM_FORMAT_RGB888,
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_RGBA8888,
+	DRM_FORMAT_ABGR8888,
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_RGBX8888,
+	DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_ARGB1555,
+	DRM_FORMAT_RGBA5551,
+	DRM_FORMAT_XRGB1555,
+	DRM_FORMAT_RGBX5551,
+	DRM_FORMAT_ARGB4444,
+	DRM_FORMAT_RGBA4444,
+	DRM_FORMAT_RGBX4444,
+	DRM_FORMAT_XRGB4444,
+	DRM_FORMAT_BGR565,
+	DRM_FORMAT_BGR888,
+	DRM_FORMAT_ABGR8888,
+	DRM_FORMAT_BGRA8888,
+	DRM_FORMAT_BGRX8888,
+	DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_ABGR1555,
+	DRM_FORMAT_BGRA5551,
+	DRM_FORMAT_XBGR1555,
+	DRM_FORMAT_BGRX5551,
+	DRM_FORMAT_ABGR4444,
+	DRM_FORMAT_BGRA4444,
+	DRM_FORMAT_BGRX4444,
+	DRM_FORMAT_XBGR4444,
+};
+
 /*************************************************************
  * DPU sub blocks config
  *************************************************************/
@@ -448,6 +493,8 @@ static const struct dpu_mdp_cfg sm8250_mdp[] = {
 			.reg_off = 0x2C4, .bit_off = 8},
 	.clk_ctrls[DPU_CLK_CTRL_REG_DMA] = {
 			.reg_off = 0x2BC, .bit_off = 20},
+	.clk_ctrls[DPU_CLK_CTRL_WB2] = {
+			.reg_off = 0x3B8, .bit_off = 24},
 	},
 };
 
@@ -1235,6 +1282,29 @@ static const struct dpu_intf_cfg qcm2290_intf[] = {
 };
 
 /*************************************************************
+ * Writeback blocks config
+ *************************************************************/
+#define WB_BLK(_name, _id, _base, _features, _clk_ctrl, \
+		__xin_id, vbif_id, _reg, _wb_done_bit) \
+	{ \
+	.name = _name, .id = _id, \
+	.base = _base, .len = 0x2c8, \
+	.features = _features, \
+	.format_list = wb2_formats, \
+	.num_formats = ARRAY_SIZE(wb2_formats), \
+	.clk_ctrl = _clk_ctrl, \
+	.xin_id = __xin_id, \
+	.vbif_idx = vbif_id, \
+	.maxlinewidth = DEFAULT_DPU_LINE_WIDTH, \
+	.intr_wb_done = DPU_IRQ_IDX(_reg, _wb_done_bit) \
+	}
+
+static const struct dpu_wb_cfg sm8250_wb[] = {
+	WB_BLK("wb_2", WB_2, 0x65000, WB_SM8250_MASK, DPU_CLK_CTRL_WB2, 6,
+			VBIF_RT, MDP_SSPP_TOP0_INTR, 4),
+};
+
+/*************************************************************
  * VBIF sub blocks config
  *************************************************************/
 /* VBIF QOS remap */
@@ -1832,6 +1902,8 @@ static void sm8250_cfg_init(struct dpu_mdss_cfg *dpu_cfg)
 		.intf = sm8150_intf,
 		.vbif_count = ARRAY_SIZE(sdm845_vbif),
 		.vbif = sdm845_vbif,
+		.wb_count = ARRAY_SIZE(sm8250_wb),
+		.wb = sm8250_wb,
 		.reg_dma_count = 1,
 		.dma_cfg = sm8250_regdma,
 		.perf = sm8250_perf_data,
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
index 866fd7a..8cb6d1f 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h
@@ -1,5 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
-/* Copyright (c) 2015-2018, 2020 The Linux Foundation. All rights reserved.
+/*
+ * Copyright (c) 2022. Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2015-2018, 2020 The Linux Foundation. All rights reserved.
  */
 
 #ifndef _DPU_HW_CATALOG_H
@@ -214,6 +216,42 @@ enum {
 };
 
 /**
+  * WB sub-blocks and features
+  * @DPU_WB_LINE_MODE        Writeback module supports line/linear mode
+  * @DPU_WB_BLOCK_MODE       Writeback module supports block mode read
+  * @DPU_WB_CHROMA_DOWN,     Writeback chroma down block,
+  * @DPU_WB_DOWNSCALE,       Writeback integer downscaler,
+  * @DPU_WB_DITHER,          Dither block
+  * @DPU_WB_TRAFFIC_SHAPER,  Writeback traffic shaper bloc
+  * @DPU_WB_UBWC,            Writeback Universal bandwidth compression
+  * @DPU_WB_YUV_CONFIG       Writeback supports output of YUV colorspace
+  * @DPU_WB_PIPE_ALPHA       Writeback supports pipe alpha
+  * @DPU_WB_XY_ROI_OFFSET    Writeback supports x/y-offset of out ROI in
+  *                          the destination image
+  * @DPU_WB_QOS,             Writeback supports QoS control, danger/safe/creq
+  * @DPU_WB_QOS_8LVL,        Writeback supports 8-level QoS control
+  * @DPU_WB_CDP              Writeback supports client driven prefetch
+  * @DPU_WB_INPUT_CTRL       Writeback supports from which pp block input pixel
+  *                          data arrives.
+  * @DPU_WB_CROP             CWB supports cropping
+  * @DPU_WB_MAX              maximum value
+  */
+enum {
+	DPU_WB_LINE_MODE = 0x1,
+	DPU_WB_BLOCK_MODE,
+	DPU_WB_UBWC,
+	DPU_WB_YUV_CONFIG,
+	DPU_WB_PIPE_ALPHA,
+	DPU_WB_XY_ROI_OFFSET,
+	DPU_WB_QOS,
+	DPU_WB_QOS_8LVL,
+	DPU_WB_CDP,
+	DPU_WB_INPUT_CTRL,
+	DPU_WB_CROP,
+	DPU_WB_MAX
+};
+
+/**
  * VBIF sub-blocks and features
  * @DPU_VBIF_QOS_OTLIM        VBIF supports OT Limit
  * @DPU_VBIF_QOS_REMAP        VBIF supports QoS priority remap
@@ -460,6 +498,7 @@ enum dpu_clk_ctrl_type {
 	DPU_CLK_CTRL_CURSOR1,
 	DPU_CLK_CTRL_INLINE_ROT0_SSPP,
 	DPU_CLK_CTRL_REG_DMA,
+	DPU_CLK_CTRL_WB2,
 	DPU_CLK_CTRL_MAX,
 };
 
@@ -608,6 +647,28 @@ struct dpu_intf_cfg  {
 };
 
 /**
+ * struct dpu_wb_cfg - information of writeback blocks
+ * @DPU_HW_BLK_INFO:    refer to the description above for DPU_HW_BLK_INFO
+ * @vbif_idx:           vbif client index
+ * @maxlinewidth:       max line width supported by writeback block
+ * @xin_id:             bus client identifier
+ * @intr_wb_done:       interrupt index for WB_DONE
+ * @format_list:	    list of formats supported by this writeback block
+ * @num_formats:	    number of formats supported by this writeback block
+ * @clk_ctrl:	        clock control identifier
+ */
+struct dpu_wb_cfg {
+	DPU_HW_BLK_INFO;
+	u8 vbif_idx;
+	u32 maxlinewidth;
+	u32 xin_id;
+	s32 intr_wb_done;
+	const u32 *format_list;
+	u32 num_formats;
+	enum dpu_clk_ctrl_type clk_ctrl;
+};
+
+/**
  * struct dpu_vbif_dynamic_ot_cfg - dynamic OT setting
  * @pps                pixel per seconds
  * @ot_limit           OT limit to use up to specified pixel per second
@@ -792,6 +853,9 @@ struct dpu_mdss_cfg {
 	u32 vbif_count;
 	const struct dpu_vbif_cfg *vbif;
 
+	u32 wb_count;
+	const struct dpu_wb_cfg *wb;
+
 	u32 reg_dma_count;
 	struct dpu_reg_dma_cfg dma_cfg;
 
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v5 04/19] drm/msm/dpu: add reset_intf_cfg operation for dpu_hw_ctl
  2022-04-25  0:31 [PATCH v5 00/19] Add writeback block support for DPU Abhinav Kumar
                   ` (2 preceding siblings ...)
  2022-04-25  0:31 ` [PATCH v5 03/19] drm/msm/dpu: add writeback blocks to the sm8250 DPU catalog Abhinav Kumar
@ 2022-04-25  0:31 ` Abhinav Kumar
  2022-04-25  0:31 ` [PATCH v5 05/19] drm/msm/dpu: rename dpu_hw_pipe_cdp_cfg to dpu_hw_cdp_cfg Abhinav Kumar
                   ` (14 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: Abhinav Kumar @ 2022-04-25  0:31 UTC (permalink / raw)
  To: freedreno
  Cc: markyacoub, liviu.dudau, Abhinav Kumar, dri-devel, swboyd,
	seanpaul, laurent.pinchart, dmitry.baryshkov, quic_jesszhan,
	quic_aravindh

Add a reset_intf_cfg operation for dpu_hw_ctl to reset the
entire CTL path by disabling each component namely layer mixer,
3d-merge and interface blocks.

changes in v3:
	- none

Signed-off-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c | 32 ++++++++++++++++++++++++++++++
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h |  8 ++++++++
 2 files changed, 40 insertions(+)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
index dc27579..524f024 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
@@ -563,6 +563,37 @@ static void dpu_hw_ctl_intf_cfg(struct dpu_hw_ctl *ctx,
 	DPU_REG_WRITE(c, CTL_TOP, intf_cfg);
 }
 
+static void dpu_hw_ctl_reset_intf_cfg_v1(struct dpu_hw_ctl *ctx,
+		struct dpu_hw_intf_cfg *cfg)
+{
+	struct dpu_hw_blk_reg_map *c = &ctx->hw;
+	u32 intf_active = 0;
+	u32 merge3d_active = 0;
+
+	/*
+	 * This API resets each portion of the CTL path namely,
+	 * clearing the sspps staged on the lm, merge_3d block,
+	 * interfaces etc to ensure clean teardown of the pipeline.
+	 * This will be used for writeback to begin with to have a
+	 * proper teardown of the writeback session but upon further
+	 * validation, this can be extended to all interfaces.
+	 */
+	if (cfg->merge_3d) {
+		merge3d_active = DPU_REG_READ(c, CTL_MERGE_3D_ACTIVE);
+		merge3d_active &= ~BIT(cfg->merge_3d - MERGE_3D_0);
+		DPU_REG_WRITE(c, CTL_MERGE_3D_ACTIVE,
+				merge3d_active);
+	}
+
+	dpu_hw_ctl_clear_all_blendstages(ctx);
+
+	if (cfg->intf) {
+		intf_active = DPU_REG_READ(c, CTL_INTF_ACTIVE);
+		intf_active &= ~BIT(cfg->intf - INTF_0);
+		DPU_REG_WRITE(c, CTL_INTF_ACTIVE, intf_active);
+	}
+}
+
 static void dpu_hw_ctl_set_fetch_pipe_active(struct dpu_hw_ctl *ctx,
 	unsigned long *fetch_active)
 {
@@ -586,6 +617,7 @@ static void _setup_ctl_ops(struct dpu_hw_ctl_ops *ops,
 	if (cap & BIT(DPU_CTL_ACTIVE_CFG)) {
 		ops->trigger_flush = dpu_hw_ctl_trigger_flush_v1;
 		ops->setup_intf_cfg = dpu_hw_ctl_intf_cfg_v1;
+		ops->reset_intf_cfg = dpu_hw_ctl_reset_intf_cfg_v1;
 		ops->update_pending_flush_intf =
 			dpu_hw_ctl_update_pending_flush_intf_v1;
 		ops->update_pending_flush_merge_3d =
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h
index 97f326d..c61a8fd 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h
@@ -140,6 +140,14 @@ struct dpu_hw_ctl_ops {
 	void (*setup_intf_cfg)(struct dpu_hw_ctl *ctx,
 		struct dpu_hw_intf_cfg *cfg);
 
+	/**
+	 * reset ctl_path interface config
+	 * @ctx    : ctl path ctx pointer
+	 * @cfg    : interface config structure pointer
+	 */
+	void (*reset_intf_cfg)(struct dpu_hw_ctl *ctx,
+			struct dpu_hw_intf_cfg *cfg);
+
 	int (*reset)(struct dpu_hw_ctl *c);
 
 	/*
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v5 05/19] drm/msm/dpu: rename dpu_hw_pipe_cdp_cfg to dpu_hw_cdp_cfg
  2022-04-25  0:31 [PATCH v5 00/19] Add writeback block support for DPU Abhinav Kumar
                   ` (3 preceding siblings ...)
  2022-04-25  0:31 ` [PATCH v5 04/19] drm/msm/dpu: add reset_intf_cfg operation for dpu_hw_ctl Abhinav Kumar
@ 2022-04-25  0:31 ` Abhinav Kumar
  2022-04-25  0:31 ` [PATCH v5 06/19] drm/msm/dpu: add dpu_hw_wb abstraction for writeback blocks Abhinav Kumar
                   ` (13 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: Abhinav Kumar @ 2022-04-25  0:31 UTC (permalink / raw)
  To: freedreno
  Cc: markyacoub, liviu.dudau, Abhinav Kumar, dri-devel, swboyd,
	seanpaul, laurent.pinchart, dmitry.baryshkov, quic_jesszhan,
	quic_aravindh

Rename dpu_hw_pipe_cdp_cfg to dpu_hw_cdp_cfg and move it
to dpu_hw_utils file so that other modules in addition to
SSPP such as writeback can use it as all the fields can
be used by writeback as well.

Suggested-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Signed-off-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c |  2 +-
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h | 18 +-----------------
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h | 15 +++++++++++++++
 drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c   |  4 ++--
 4 files changed, 19 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c
index 09cdc35..0a0864d 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c
@@ -627,7 +627,7 @@ static void dpu_hw_sspp_setup_qos_ctrl(struct dpu_hw_pipe *ctx,
 }
 
 static void dpu_hw_sspp_setup_cdp(struct dpu_hw_pipe *ctx,
-		struct dpu_hw_pipe_cdp_cfg *cfg,
+		struct dpu_hw_cdp_cfg *cfg,
 		enum dpu_sspp_multirect_index index)
 {
 	u32 idx;
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h
index 92b071b..a81e166 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h
@@ -193,22 +193,6 @@ enum {
 };
 
 /**
- * struct dpu_hw_pipe_cdp_cfg : CDP configuration
- * @enable: true to enable CDP
- * @ubwc_meta_enable: true to enable ubwc metadata preload
- * @tile_amortize_enable: true to enable amortization control for tile format
- * @preload_ahead: number of request to preload ahead
- *	DPU_SSPP_CDP_PRELOAD_AHEAD_32,
- *	DPU_SSPP_CDP_PRELOAD_AHEAD_64
- */
-struct dpu_hw_pipe_cdp_cfg {
-	bool enable;
-	bool ubwc_meta_enable;
-	bool tile_amortize_enable;
-	u32 preload_ahead;
-};
-
-/**
  * struct dpu_hw_pipe_ts_cfg - traffic shaper configuration
  * @size: size to prefill in bytes, or zero to disable
  * @time: time to prefill in usec, or zero to disable
@@ -359,7 +343,7 @@ struct dpu_hw_sspp_ops {
 	 * @index: rectangle index in multirect
 	 */
 	void (*setup_cdp)(struct dpu_hw_pipe *ctx,
-			struct dpu_hw_pipe_cdp_cfg *cfg,
+			struct dpu_hw_cdp_cfg *cfg,
 			enum dpu_sspp_multirect_index index);
 };
 
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h
index 3913475..a200df1 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h
@@ -298,6 +298,21 @@ struct dpu_drm_scaler_v2 {
 	struct dpu_drm_de_v1 de;
 };
 
+/**
+ * struct dpu_hw_cdp_cfg : CDP configuration
+ * @enable: true to enable CDP
+ * @ubwc_meta_enable: true to enable ubwc metadata preload
+ * @tile_amortize_enable: true to enable amortization control for tile format
+ * @preload_ahead: number of request to preload ahead
+ *	DPU_*_CDP_PRELOAD_AHEAD_32,
+ *	DPU_*_CDP_PRELOAD_AHEAD_64
+ */
+struct dpu_hw_cdp_cfg {
+	bool enable;
+	bool ubwc_meta_enable;
+	bool tile_amortize_enable;
+	u32 preload_ahead;
+};
 
 u32 *dpu_hw_util_get_log_mask_ptr(void);
 
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
index c77c3d9d..08b8c64 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
@@ -1246,9 +1246,9 @@ static void dpu_plane_sspp_atomic_update(struct drm_plane *plane)
 				pstate->multirect_index);
 
 		if (pdpu->pipe_hw->ops.setup_cdp) {
-			struct dpu_hw_pipe_cdp_cfg cdp_cfg;
+			struct dpu_hw_cdp_cfg cdp_cfg;
 
-			memset(&cdp_cfg, 0, sizeof(struct dpu_hw_pipe_cdp_cfg));
+			memset(&cdp_cfg, 0, sizeof(struct dpu_hw_cdp_cfg));
 
 			cdp_cfg.enable = pdpu->catalog->perf.cdp_cfg
 					[DPU_PERF_CDP_USAGE_RT].rd_enable;
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v5 06/19] drm/msm/dpu: add dpu_hw_wb abstraction for writeback blocks
  2022-04-25  0:31 [PATCH v5 00/19] Add writeback block support for DPU Abhinav Kumar
                   ` (4 preceding siblings ...)
  2022-04-25  0:31 ` [PATCH v5 05/19] drm/msm/dpu: rename dpu_hw_pipe_cdp_cfg to dpu_hw_cdp_cfg Abhinav Kumar
@ 2022-04-25  0:31 ` Abhinav Kumar
  2022-04-25  0:31 ` [PATCH v5 07/19] drm/msm/dpu: add writeback blocks to DPU RM Abhinav Kumar
                   ` (12 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: Abhinav Kumar @ 2022-04-25  0:31 UTC (permalink / raw)
  To: freedreno
  Cc: markyacoub, liviu.dudau, Abhinav Kumar, dri-devel, swboyd,
	seanpaul, laurent.pinchart, dmitry.baryshkov, quic_jesszhan,
	quic_aravindh

Add the dpu_hw_wb abstraction to program registers related to the
writeback block. These will be invoked once all the configuration
is set and ready to be programmed to the registers.

changes in v3:
	- start using the common struct dpu_hw_cdp_cfg
	- leave a comment about DPU non-DPU_WB_QOS_8LVL chipsets

Signed-off-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
 drivers/gpu/drm/msm/Makefile              |   1 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.c | 279 ++++++++++++++++++++++++++++++
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.h | 115 ++++++++++++
 3 files changed, 395 insertions(+)
 create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.c
 create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.h

diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index d5ca2e6..ca779c1 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -74,6 +74,7 @@ msm-$(CONFIG_DRM_MSM_DPU) += \
 	disp/dpu1/dpu_hw_top.o \
 	disp/dpu1/dpu_hw_util.o \
 	disp/dpu1/dpu_hw_vbif.o \
+	disp/dpu1/dpu_hw_wb.o \
 	disp/dpu1/dpu_kms.o \
 	disp/dpu1/dpu_plane.o \
 	disp/dpu1/dpu_rm.o \
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.c
new file mode 100644
index 0000000..bcccce2
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.c
@@ -0,0 +1,279 @@
+// SPDX-License-Identifier: GPL-2.0-only
+ /*
+  * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved
+  */
+
+#include "dpu_hw_mdss.h"
+#include "dpu_hwio.h"
+#include "dpu_hw_catalog.h"
+#include "dpu_hw_wb.h"
+#include "dpu_formats.h"
+#include "dpu_kms.h"
+
+#define WB_DST_FORMAT                         0x000
+#define WB_DST_OP_MODE                        0x004
+#define WB_DST_PACK_PATTERN                   0x008
+#define WB_DST0_ADDR                          0x00C
+#define WB_DST1_ADDR                          0x010
+#define WB_DST2_ADDR                          0x014
+#define WB_DST3_ADDR                          0x018
+#define WB_DST_YSTRIDE0                       0x01C
+#define WB_DST_YSTRIDE1                       0x020
+#define WB_DST_YSTRIDE1                       0x020
+#define WB_DST_DITHER_BITDEPTH                0x024
+#define WB_DST_MATRIX_ROW0                    0x030
+#define WB_DST_MATRIX_ROW1                    0x034
+#define WB_DST_MATRIX_ROW2                    0x038
+#define WB_DST_MATRIX_ROW3                    0x03C
+#define WB_DST_WRITE_CONFIG                   0x048
+#define WB_ROTATION_DNSCALER                  0x050
+#define WB_ROTATOR_PIPE_DOWNSCALER            0x054
+#define WB_N16_INIT_PHASE_X_C03               0x060
+#define WB_N16_INIT_PHASE_X_C12               0x064
+#define WB_N16_INIT_PHASE_Y_C03               0x068
+#define WB_N16_INIT_PHASE_Y_C12               0x06C
+#define WB_OUT_SIZE                           0x074
+#define WB_ALPHA_X_VALUE                      0x078
+#define WB_DANGER_LUT                         0x084
+#define WB_SAFE_LUT                           0x088
+#define WB_QOS_CTRL                           0x090
+#define WB_CREQ_LUT_0                         0x098
+#define WB_CREQ_LUT_1                         0x09C
+#define WB_UBWC_STATIC_CTRL                   0x144
+#define WB_MUX                                0x150
+#define WB_CROP_CTRL                          0x154
+#define WB_CROP_OFFSET                        0x158
+#define WB_CSC_BASE                           0x260
+#define WB_DST_ADDR_SW_STATUS                 0x2B0
+#define WB_CDP_CNTL                           0x2B4
+#define WB_OUT_IMAGE_SIZE                     0x2C0
+#define WB_OUT_XY                             0x2C4
+
+/* WB_QOS_CTRL */
+#define WB_QOS_CTRL_DANGER_SAFE_EN            BIT(0)
+
+static const struct dpu_wb_cfg *_wb_offset(enum dpu_wb wb,
+		const struct dpu_mdss_cfg *m, void __iomem *addr,
+		struct dpu_hw_blk_reg_map *b)
+{
+	int i;
+
+	for (i = 0; i < m->wb_count; i++) {
+		if (wb == m->wb[i].id) {
+			b->base_off = addr;
+			b->blk_off = m->wb[i].base;
+			b->length = m->wb[i].len;
+			b->hwversion = m->hwversion;
+			return &m->wb[i];
+		}
+	}
+	return ERR_PTR(-EINVAL);
+}
+
+static void dpu_hw_wb_setup_outaddress(struct dpu_hw_wb *ctx,
+		struct dpu_hw_wb_cfg *data)
+{
+	struct dpu_hw_blk_reg_map *c = &ctx->hw;
+
+	DPU_REG_WRITE(c, WB_DST0_ADDR, data->dest.plane_addr[0]);
+	DPU_REG_WRITE(c, WB_DST1_ADDR, data->dest.plane_addr[1]);
+	DPU_REG_WRITE(c, WB_DST2_ADDR, data->dest.plane_addr[2]);
+	DPU_REG_WRITE(c, WB_DST3_ADDR, data->dest.plane_addr[3]);
+}
+
+static void dpu_hw_wb_setup_format(struct dpu_hw_wb *ctx,
+		struct dpu_hw_wb_cfg *data)
+{
+	struct dpu_hw_blk_reg_map *c = &ctx->hw;
+	const struct dpu_format *fmt = data->dest.format;
+	u32 dst_format, pattern, ystride0, ystride1, outsize, chroma_samp;
+	u32 write_config = 0;
+	u32 opmode = 0;
+	u32 dst_addr_sw = 0;
+
+	chroma_samp = fmt->chroma_sample;
+
+	dst_format = (chroma_samp << 23) |
+		(fmt->fetch_planes << 19) |
+		(fmt->bits[C3_ALPHA] << 6) |
+		(fmt->bits[C2_R_Cr] << 4) |
+		(fmt->bits[C1_B_Cb] << 2) |
+		(fmt->bits[C0_G_Y] << 0);
+
+	if (fmt->bits[C3_ALPHA] || fmt->alpha_enable) {
+		dst_format |= BIT(8); /* DSTC3_EN */
+		if (!fmt->alpha_enable ||
+			!(ctx->caps->features & BIT(DPU_WB_PIPE_ALPHA)))
+			dst_format |= BIT(14); /* DST_ALPHA_X */
+	}
+
+	pattern = (fmt->element[3] << 24) |
+		(fmt->element[2] << 16) |
+		(fmt->element[1] << 8)  |
+		(fmt->element[0] << 0);
+
+	dst_format |= (fmt->unpack_align_msb << 18) |
+		(fmt->unpack_tight << 17) |
+		((fmt->unpack_count - 1) << 12) |
+		((fmt->bpp - 1) << 9);
+
+	ystride0 = data->dest.plane_pitch[0] |
+		(data->dest.plane_pitch[1] << 16);
+	ystride1 = data->dest.plane_pitch[2] |
+	(data->dest.plane_pitch[3] << 16);
+
+	if (drm_rect_height(&data->roi) && drm_rect_width(&data->roi))
+		outsize = (drm_rect_height(&data->roi) << 16) | drm_rect_width(&data->roi);
+	else
+		outsize = (data->dest.height << 16) | data->dest.width;
+
+	DPU_REG_WRITE(c, WB_ALPHA_X_VALUE, 0xFF);
+	DPU_REG_WRITE(c, WB_DST_FORMAT, dst_format);
+	DPU_REG_WRITE(c, WB_DST_OP_MODE, opmode);
+	DPU_REG_WRITE(c, WB_DST_PACK_PATTERN, pattern);
+	DPU_REG_WRITE(c, WB_DST_YSTRIDE0, ystride0);
+	DPU_REG_WRITE(c, WB_DST_YSTRIDE1, ystride1);
+	DPU_REG_WRITE(c, WB_OUT_SIZE, outsize);
+	DPU_REG_WRITE(c, WB_DST_WRITE_CONFIG, write_config);
+	DPU_REG_WRITE(c, WB_DST_ADDR_SW_STATUS, dst_addr_sw);
+}
+
+static void dpu_hw_wb_roi(struct dpu_hw_wb *ctx, struct dpu_hw_wb_cfg *wb)
+{
+	struct dpu_hw_blk_reg_map *c = &ctx->hw;
+	u32 image_size, out_size, out_xy;
+
+	image_size = (wb->dest.height << 16) | wb->dest.width;
+	out_xy = 0;
+	out_size = (drm_rect_height(&wb->roi) << 16) | drm_rect_width(&wb->roi);
+
+	DPU_REG_WRITE(c, WB_OUT_IMAGE_SIZE, image_size);
+	DPU_REG_WRITE(c, WB_OUT_XY, out_xy);
+	DPU_REG_WRITE(c, WB_OUT_SIZE, out_size);
+}
+
+static void dpu_hw_wb_setup_qos_lut(struct dpu_hw_wb *ctx,
+		struct dpu_hw_wb_qos_cfg *cfg)
+{
+	struct dpu_hw_blk_reg_map *c = &ctx->hw;
+	u32 qos_ctrl = 0;
+
+	if (!ctx || !cfg)
+		return;
+
+	DPU_REG_WRITE(c, WB_DANGER_LUT, cfg->danger_lut);
+	DPU_REG_WRITE(c, WB_SAFE_LUT, cfg->safe_lut);
+
+	/*
+	 * for chipsets not using DPU_WB_QOS_8LVL but still using DPU
+	 * driver such as msm8998, the reset value of WB_CREQ_LUT is
+	 * sufficient for writeback to work. SW doesn't need to explicitly
+	 * program a value.
+	 */
+	if (ctx->caps && test_bit(DPU_WB_QOS_8LVL, &ctx->caps->features)) {
+		DPU_REG_WRITE(c, WB_CREQ_LUT_0, cfg->creq_lut);
+		DPU_REG_WRITE(c, WB_CREQ_LUT_1, cfg->creq_lut >> 32);
+	}
+
+	if (cfg->danger_safe_en)
+		qos_ctrl |= WB_QOS_CTRL_DANGER_SAFE_EN;
+
+	DPU_REG_WRITE(c, WB_QOS_CTRL, qos_ctrl);
+}
+
+static void dpu_hw_wb_setup_cdp(struct dpu_hw_wb *ctx,
+		struct dpu_hw_cdp_cfg *cfg)
+{
+	struct dpu_hw_blk_reg_map *c;
+	u32 cdp_cntl = 0;
+
+	if (!ctx || !cfg)
+		return;
+
+	c = &ctx->hw;
+
+	if (cfg->enable)
+		cdp_cntl |= BIT(0);
+	if (cfg->ubwc_meta_enable)
+		cdp_cntl |= BIT(1);
+	if (cfg->preload_ahead == DPU_WB_CDP_PRELOAD_AHEAD_64)
+		cdp_cntl |= BIT(3);
+
+	DPU_REG_WRITE(c, WB_CDP_CNTL, cdp_cntl);
+}
+
+static void dpu_hw_wb_bind_pingpong_blk(
+		struct dpu_hw_wb *ctx,
+		bool enable, const enum dpu_pingpong pp)
+{
+	struct dpu_hw_blk_reg_map *c;
+	int mux_cfg;
+
+	if (!ctx)
+		return;
+
+	c = &ctx->hw;
+
+	mux_cfg = DPU_REG_READ(c, WB_MUX);
+	mux_cfg &= ~0xf;
+
+	if (enable)
+		mux_cfg |= (pp - PINGPONG_0) & 0x7;
+	else
+		mux_cfg |= 0xf;
+
+	DPU_REG_WRITE(c, WB_MUX, mux_cfg);
+}
+
+static void _setup_wb_ops(struct dpu_hw_wb_ops *ops,
+		unsigned long features)
+{
+	ops->setup_outaddress = dpu_hw_wb_setup_outaddress;
+	ops->setup_outformat = dpu_hw_wb_setup_format;
+
+	if (test_bit(DPU_WB_XY_ROI_OFFSET, &features))
+		ops->setup_roi = dpu_hw_wb_roi;
+
+	if (test_bit(DPU_WB_QOS, &features))
+		ops->setup_qos_lut = dpu_hw_wb_setup_qos_lut;
+
+	if (test_bit(DPU_WB_CDP, &features))
+		ops->setup_cdp = dpu_hw_wb_setup_cdp;
+
+	if (test_bit(DPU_WB_INPUT_CTRL, &features))
+		ops->bind_pingpong_blk = dpu_hw_wb_bind_pingpong_blk;
+}
+
+struct dpu_hw_wb *dpu_hw_wb_init(enum dpu_wb idx,
+		void __iomem *addr, const struct dpu_mdss_cfg *m)
+{
+	struct dpu_hw_wb *c;
+	const struct dpu_wb_cfg *cfg;
+
+	if (!addr || !m)
+		return ERR_PTR(-EINVAL);
+
+	c = kzalloc(sizeof(*c), GFP_KERNEL);
+	if (!c)
+		return ERR_PTR(-ENOMEM);
+
+	cfg = _wb_offset(idx, m, addr, &c->hw);
+	if (IS_ERR(cfg)) {
+		WARN(1, "Unable to find wb idx=%d\n", idx);
+		kfree(c);
+		return ERR_PTR(-EINVAL);
+	}
+
+	/* Assign ops */
+	c->mdp = &m->mdp[0];
+	c->idx = idx;
+	c->caps = cfg;
+	_setup_wb_ops(&c->ops, c->caps->features);
+
+	return c;
+}
+
+void dpu_hw_wb_destroy(struct dpu_hw_wb *hw_wb)
+{
+	kfree(hw_wb);
+}
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.h
new file mode 100644
index 0000000..3ff5a48
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.h
@@ -0,0 +1,115 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved
+ */
+
+#ifndef _DPU_HW_WB_H
+#define _DPU_HW_WB_H
+
+#include "dpu_hw_catalog.h"
+#include "dpu_hw_mdss.h"
+#include "dpu_hw_top.h"
+#include "dpu_hw_util.h"
+#include "dpu_hw_pingpong.h"
+
+struct dpu_hw_wb;
+
+struct dpu_hw_wb_cfg {
+	struct dpu_hw_fmt_layout dest;
+	enum dpu_intf_mode intf_mode;
+	struct drm_rect roi;
+	struct drm_rect crop;
+};
+
+/**
+ * enum CDP preload ahead address size
+ */
+enum {
+	DPU_WB_CDP_PRELOAD_AHEAD_32,
+	DPU_WB_CDP_PRELOAD_AHEAD_64
+};
+
+/**
+ * struct dpu_hw_wb_qos_cfg : Writeback pipe QoS configuration
+ * @danger_lut: LUT for generate danger level based on fill level
+ * @safe_lut: LUT for generate safe level based on fill level
+ * @creq_lut: LUT for generate creq level based on fill level
+ * @danger_safe_en: enable danger safe generation
+ */
+struct dpu_hw_wb_qos_cfg {
+	u32 danger_lut;
+	u32 safe_lut;
+	u64 creq_lut;
+	bool danger_safe_en;
+};
+
+/**
+ *
+ * struct dpu_hw_wb_ops : Interface to the wb hw driver functions
+ *  Assumption is these functions will be called after clocks are enabled
+ *  @setup_outaddress: setup output address from the writeback job
+ *  @setup_outformat: setup output format of writeback block from writeback job
+ *  @setup_qos_lut:   setup qos LUT for writeback block based on input
+ *  @setup_cdp:       setup chroma down prefetch block for writeback block
+ *  @bind_pingpong_blk: enable/disable the connection with ping-pong block
+ */
+struct dpu_hw_wb_ops {
+	void (*setup_outaddress)(struct dpu_hw_wb *ctx,
+			struct dpu_hw_wb_cfg *wb);
+
+	void (*setup_outformat)(struct dpu_hw_wb *ctx,
+			struct dpu_hw_wb_cfg *wb);
+
+	void (*setup_roi)(struct dpu_hw_wb *ctx,
+			struct dpu_hw_wb_cfg *wb);
+
+	void (*setup_qos_lut)(struct dpu_hw_wb *ctx,
+			struct dpu_hw_wb_qos_cfg *cfg);
+
+	void (*setup_cdp)(struct dpu_hw_wb *ctx,
+			struct dpu_hw_cdp_cfg *cfg);
+
+	void (*bind_pingpong_blk)(struct dpu_hw_wb *ctx,
+			bool enable, const enum dpu_pingpong pp);
+};
+
+/**
+ * struct dpu_hw_wb : WB driver object
+ * @hw: block hardware details
+ * @mdp: pointer to associated mdp portion of the catalog
+ * @idx: hardware index number within type
+ * @wb_hw_caps: hardware capabilities
+ * @ops: function pointers
+ * @hw_mdp: MDP top level hardware block
+ */
+struct dpu_hw_wb {
+	struct dpu_hw_blk_reg_map hw;
+	const struct dpu_mdp_cfg *mdp;
+
+	/* wb path */
+	int idx;
+	const struct dpu_wb_cfg *caps;
+
+	/* ops */
+	struct dpu_hw_wb_ops ops;
+
+	struct dpu_hw_mdp *hw_mdp;
+};
+
+/**
+ * dpu_hw_wb_init(): Initializes and return writeback hw driver object.
+ * @idx:  wb_path index for which driver object is required
+ * @addr: mapped register io address of MDP
+ * @m :   pointer to mdss catalog data
+ */
+struct dpu_hw_wb *dpu_hw_wb_init(enum dpu_wb idx,
+		void __iomem *addr,
+		const struct dpu_mdss_cfg *m);
+
+/**
+ * dpu_hw_wb_destroy(): Destroy writeback hw driver object.
+ * @hw_wb:  Pointer to writeback hw driver object
+ */
+void dpu_hw_wb_destroy(struct dpu_hw_wb *hw_wb);
+
+#endif /*_DPU_HW_WB_H */
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v5 07/19] drm/msm/dpu: add writeback blocks to DPU RM
  2022-04-25  0:31 [PATCH v5 00/19] Add writeback block support for DPU Abhinav Kumar
                   ` (5 preceding siblings ...)
  2022-04-25  0:31 ` [PATCH v5 06/19] drm/msm/dpu: add dpu_hw_wb abstraction for writeback blocks Abhinav Kumar
@ 2022-04-25  0:31 ` Abhinav Kumar
  2022-04-25  0:31 ` [PATCH v5 08/19] drm/msm/dpu: add changes to support writeback in hw_ctl Abhinav Kumar
                   ` (11 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: Abhinav Kumar @ 2022-04-25  0:31 UTC (permalink / raw)
  To: freedreno
  Cc: markyacoub, liviu.dudau, Abhinav Kumar, dri-devel, swboyd,
	seanpaul, laurent.pinchart, dmitry.baryshkov, quic_jesszhan,
	quic_aravindh

Add writeback blocks to DPU resource manager so that
the encoders can directly request them through RM.

changes in v4:
	- absorb dpu_rm.h header change from [1]
	- since its a trivial change absorbed from an approved
	  patch, preserving the previous ack on this

[1] https://patchwork.freedesktop.org/patch/483099/?series=102964&rev=2

Signed-off-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c | 22 ++++++++++++++++++++++
 drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h | 12 ++++++++++++
 2 files changed, 34 insertions(+)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
index 0e6634b..06f03e7 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c
@@ -9,6 +9,7 @@
 #include "dpu_hw_ctl.h"
 #include "dpu_hw_pingpong.h"
 #include "dpu_hw_intf.h"
+#include "dpu_hw_wb.h"
 #include "dpu_hw_dspp.h"
 #include "dpu_hw_merge3d.h"
 #include "dpu_hw_dsc.h"
@@ -87,6 +88,9 @@ int dpu_rm_destroy(struct dpu_rm *rm)
 		}
 	}
 
+	for (i = 0; i < ARRAY_SIZE(rm->hw_wb); i++)
+		dpu_hw_wb_destroy(rm->hw_wb[i]);
+
 	return 0;
 }
 
@@ -186,6 +190,24 @@ int dpu_rm_init(struct dpu_rm *rm,
 		rm->hw_intf[intf->id - INTF_0] = hw;
 	}
 
+	for (i = 0; i < cat->wb_count; i++) {
+		struct dpu_hw_wb *hw;
+		const struct dpu_wb_cfg *wb = &cat->wb[i];
+
+		if (wb->id < WB_0 || wb->id >= WB_MAX) {
+			DPU_ERROR("skip intf %d with invalid id\n", wb->id);
+			continue;
+		}
+
+		hw = dpu_hw_wb_init(wb->id, mmio, cat);
+		if (IS_ERR(hw)) {
+			rc = PTR_ERR(hw);
+			DPU_ERROR("failed wb object creation: err %d\n", rc);
+			goto fail;
+		}
+		rm->hw_wb[wb->id - WB_0] = hw;
+	}
+
 	for (i = 0; i < cat->ctl_count; i++) {
 		struct dpu_hw_ctl *hw;
 		const struct dpu_ctl_cfg *ctl = &cat->ctl[i];
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
index 32e0d8a..2f34a31 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h
@@ -19,6 +19,7 @@ struct dpu_global_state;
  * @mixer_blks: array of layer mixer hardware resources
  * @ctl_blks: array of ctl hardware resources
  * @hw_intf: array of intf hardware resources
+ * @hw_wb: array of wb hardware resources
  * @dspp_blks: array of dspp hardware resources
  */
 struct dpu_rm {
@@ -26,6 +27,7 @@ struct dpu_rm {
 	struct dpu_hw_blk *mixer_blks[LM_MAX - LM_0];
 	struct dpu_hw_blk *ctl_blks[CTL_MAX - CTL_0];
 	struct dpu_hw_intf *hw_intf[INTF_MAX - INTF_0];
+	struct dpu_hw_wb *hw_wb[WB_MAX - WB_0];
 	struct dpu_hw_blk *dspp_blks[DSPP_MAX - DSPP_0];
 	struct dpu_hw_blk *merge_3d_blks[MERGE_3D_MAX - MERGE_3D_0];
 	struct dpu_hw_blk *dsc_blks[DSC_MAX - DSC_0];
@@ -96,5 +98,15 @@ static inline struct dpu_hw_intf *dpu_rm_get_intf(struct dpu_rm *rm, enum dpu_in
 	return rm->hw_intf[intf_idx - INTF_0];
 }
 
+/**
+ * dpu_rm_get_wb - Return a struct dpu_hw_wb instance given it's index.
+ * @rm: DPU Resource Manager handle
+ * @wb_idx: WB index
+ */
+static inline struct dpu_hw_wb *dpu_rm_get_wb(struct dpu_rm *rm, enum dpu_wb wb_idx)
+{
+	return rm->hw_wb[wb_idx - WB_0];
+}
+
 #endif /* __DPU_RM_H__ */
 
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v5 08/19] drm/msm/dpu: add changes to support writeback in hw_ctl
  2022-04-25  0:31 [PATCH v5 00/19] Add writeback block support for DPU Abhinav Kumar
                   ` (6 preceding siblings ...)
  2022-04-25  0:31 ` [PATCH v5 07/19] drm/msm/dpu: add writeback blocks to DPU RM Abhinav Kumar
@ 2022-04-25  0:31 ` Abhinav Kumar
  2022-04-25  0:32 ` [PATCH v5 09/19] drm/msm/dpu: add an API to reset the encoder related hw blocks Abhinav Kumar
                   ` (10 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: Abhinav Kumar @ 2022-04-25  0:31 UTC (permalink / raw)
  To: freedreno
  Cc: markyacoub, liviu.dudau, Abhinav Kumar, dri-devel, swboyd,
	seanpaul, laurent.pinchart, dmitry.baryshkov, quic_jesszhan,
	quic_aravindh

Add changes to support writeback module in the dpu_hw_ctl
interface.

changes in v4:
	- fix the copyright year order

Signed-off-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c | 52 ++++++++++++++++++++++++++++--
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h | 13 ++++++++
 2 files changed, 63 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
index 524f024..254fdf0 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #include <linux/delay.h>
@@ -23,10 +24,12 @@
 #define   CTL_SW_RESET                  0x030
 #define   CTL_LAYER_EXTN_OFFSET         0x40
 #define   CTL_MERGE_3D_ACTIVE           0x0E4
+#define   CTL_WB_ACTIVE                 0x0EC
 #define   CTL_INTF_ACTIVE               0x0F4
 #define   CTL_MERGE_3D_FLUSH            0x100
 #define   CTL_DSC_ACTIVE                0x0E8
 #define   CTL_DSC_FLUSH                0x104
+#define   CTL_WB_FLUSH                  0x108
 #define   CTL_INTF_FLUSH                0x110
 #define   CTL_INTF_MASTER               0x134
 #define   CTL_FETCH_PIPE_ACTIVE         0x0FC
@@ -38,6 +41,7 @@
 #define  MERGE_3D_IDX   23
 #define  DSC_IDX        22
 #define  INTF_IDX       31
+#define WB_IDX          16
 #define CTL_INVALID_BIT                 0xffff
 #define CTL_DEFAULT_GROUP_ID		0xf
 
@@ -135,6 +139,9 @@ static inline void dpu_hw_ctl_trigger_flush_v1(struct dpu_hw_ctl *ctx)
 	if (ctx->pending_flush_mask & BIT(INTF_IDX))
 		DPU_REG_WRITE(&ctx->hw, CTL_INTF_FLUSH,
 				ctx->pending_intf_flush_mask);
+	if (ctx->pending_flush_mask & BIT(WB_IDX))
+		DPU_REG_WRITE(&ctx->hw, CTL_WB_FLUSH,
+				ctx->pending_wb_flush_mask);
 
 	DPU_REG_WRITE(&ctx->hw, CTL_FLUSH, ctx->pending_flush_mask);
 }
@@ -255,6 +262,26 @@ static void dpu_hw_ctl_update_pending_flush_intf(struct dpu_hw_ctl *ctx,
 	}
 }
 
+static void dpu_hw_ctl_update_pending_flush_wb(struct dpu_hw_ctl *ctx,
+		enum dpu_wb wb)
+{
+	switch (wb) {
+	case WB_0:
+	case WB_1:
+	case WB_2:
+		ctx->pending_flush_mask |= BIT(WB_IDX);
+	default:
+		break;
+	}
+}
+
+static void dpu_hw_ctl_update_pending_flush_wb_v1(struct dpu_hw_ctl *ctx,
+		enum dpu_wb wb)
+{
+	ctx->pending_wb_flush_mask |= BIT(wb - WB_0);
+	ctx->pending_flush_mask |= BIT(WB_IDX);
+}
+
 static void dpu_hw_ctl_update_pending_flush_intf_v1(struct dpu_hw_ctl *ctx,
 		enum dpu_intf intf)
 {
@@ -504,6 +531,7 @@ static void dpu_hw_ctl_intf_cfg_v1(struct dpu_hw_ctl *ctx,
 {
 	struct dpu_hw_blk_reg_map *c = &ctx->hw;
 	u32 intf_active = 0;
+	u32 wb_active = 0;
 	u32 mode_sel = 0;
 
 	/* CTL_TOP[31:28] carries group_id to collate CTL paths
@@ -520,10 +548,18 @@ static void dpu_hw_ctl_intf_cfg_v1(struct dpu_hw_ctl *ctx,
 		mode_sel |= BIT(17);
 
 	intf_active = DPU_REG_READ(c, CTL_INTF_ACTIVE);
-	intf_active |= BIT(cfg->intf - INTF_0);
+	wb_active = DPU_REG_READ(c, CTL_WB_ACTIVE);
+
+	if (cfg->intf)
+		intf_active |= BIT(cfg->intf - INTF_0);
+
+	if (cfg->wb)
+		wb_active |= BIT(cfg->wb - WB_0);
 
 	DPU_REG_WRITE(c, CTL_TOP, mode_sel);
 	DPU_REG_WRITE(c, CTL_INTF_ACTIVE, intf_active);
+	DPU_REG_WRITE(c, CTL_WB_ACTIVE, wb_active);
+
 	if (cfg->merge_3d)
 		DPU_REG_WRITE(c, CTL_MERGE_3D_ACTIVE,
 			      BIT(cfg->merge_3d - MERGE_3D_0));
@@ -546,6 +582,9 @@ static void dpu_hw_ctl_intf_cfg(struct dpu_hw_ctl *ctx,
 		intf_cfg |= (cfg->mode_3d - 0x1) << 20;
 	}
 
+	if (cfg->wb)
+		intf_cfg |= (cfg->wb & 0x3) + 2;
+
 	switch (cfg->intf_mode_sel) {
 	case DPU_CTL_MODE_SEL_VID:
 		intf_cfg &= ~BIT(17);
@@ -568,12 +607,13 @@ static void dpu_hw_ctl_reset_intf_cfg_v1(struct dpu_hw_ctl *ctx,
 {
 	struct dpu_hw_blk_reg_map *c = &ctx->hw;
 	u32 intf_active = 0;
+	u32 wb_active = 0;
 	u32 merge3d_active = 0;
 
 	/*
 	 * This API resets each portion of the CTL path namely,
 	 * clearing the sspps staged on the lm, merge_3d block,
-	 * interfaces etc to ensure clean teardown of the pipeline.
+	 * interfaces , writeback etc to ensure clean teardown of the pipeline.
 	 * This will be used for writeback to begin with to have a
 	 * proper teardown of the writeback session but upon further
 	 * validation, this can be extended to all interfaces.
@@ -592,6 +632,12 @@ static void dpu_hw_ctl_reset_intf_cfg_v1(struct dpu_hw_ctl *ctx,
 		intf_active &= ~BIT(cfg->intf - INTF_0);
 		DPU_REG_WRITE(c, CTL_INTF_ACTIVE, intf_active);
 	}
+
+	if (cfg->wb) {
+		wb_active = DPU_REG_READ(c, CTL_WB_ACTIVE);
+		wb_active &= ~BIT(cfg->wb - WB_0);
+		DPU_REG_WRITE(c, CTL_WB_ACTIVE, wb_active);
+	}
 }
 
 static void dpu_hw_ctl_set_fetch_pipe_active(struct dpu_hw_ctl *ctx,
@@ -622,11 +668,13 @@ static void _setup_ctl_ops(struct dpu_hw_ctl_ops *ops,
 			dpu_hw_ctl_update_pending_flush_intf_v1;
 		ops->update_pending_flush_merge_3d =
 			dpu_hw_ctl_update_pending_flush_merge_3d_v1;
+		ops->update_pending_flush_wb = dpu_hw_ctl_update_pending_flush_wb_v1;
 	} else {
 		ops->trigger_flush = dpu_hw_ctl_trigger_flush;
 		ops->setup_intf_cfg = dpu_hw_ctl_intf_cfg;
 		ops->update_pending_flush_intf =
 			dpu_hw_ctl_update_pending_flush_intf;
+		ops->update_pending_flush_wb = dpu_hw_ctl_update_pending_flush_wb;
 	}
 	ops->clear_pending_flush = dpu_hw_ctl_clear_pending_flush;
 	ops->update_pending_flush = dpu_hw_ctl_update_pending_flush;
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h
index c61a8fd..5755307 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h
@@ -1,5 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _DPU_HW_CTL_H
@@ -44,6 +45,7 @@ struct dpu_hw_stage_cfg {
  */
 struct dpu_hw_intf_cfg {
 	enum dpu_intf intf;
+	enum dpu_wb wb;
 	enum dpu_3d_blend_mode mode_3d;
 	enum dpu_merge_3d merge_3d;
 	enum dpu_ctl_mode_sel intf_mode_sel;
@@ -102,6 +104,15 @@ struct dpu_hw_ctl_ops {
 		u32 flushbits);
 
 	/**
+	 * OR in the given flushbits to the cached pending_(wb_)flush_mask
+	 * No effect on hardware
+	 * @ctx       : ctl path ctx pointer
+	 * @blk       : writeback block index
+	 */
+	void (*update_pending_flush_wb)(struct dpu_hw_ctl *ctx,
+		enum dpu_wb blk);
+
+	/**
 	 * OR in the given flushbits to the cached pending_(intf_)flush_mask
 	 * No effect on hardware
 	 * @ctx       : ctl path ctx pointer
@@ -199,6 +210,7 @@ struct dpu_hw_ctl_ops {
  * @mixer_hw_caps: mixer hardware capabilities
  * @pending_flush_mask: storage for pending ctl_flush managed via ops
  * @pending_intf_flush_mask: pending INTF flush
+ * @pending_wb_flush_mask: pending WB flush
  * @ops: operation list
  */
 struct dpu_hw_ctl {
@@ -212,6 +224,7 @@ struct dpu_hw_ctl {
 	const struct dpu_lm_cfg *mixer_hw_caps;
 	u32 pending_flush_mask;
 	u32 pending_intf_flush_mask;
+	u32 pending_wb_flush_mask;
 	u32 pending_merge_3d_flush_mask;
 
 	/* ops */
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v5 09/19] drm/msm/dpu: add an API to reset the encoder related hw blocks
  2022-04-25  0:31 [PATCH v5 00/19] Add writeback block support for DPU Abhinav Kumar
                   ` (7 preceding siblings ...)
  2022-04-25  0:31 ` [PATCH v5 08/19] drm/msm/dpu: add changes to support writeback in hw_ctl Abhinav Kumar
@ 2022-04-25  0:32 ` Abhinav Kumar
  2022-04-25  0:32 ` [PATCH v5 10/19] drm/msm/dpu: make changes to dpu_encoder to support virtual encoder Abhinav Kumar
                   ` (9 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: Abhinav Kumar @ 2022-04-25  0:32 UTC (permalink / raw)
  To: freedreno
  Cc: markyacoub, liviu.dudau, Abhinav Kumar, dri-devel, swboyd,
	seanpaul, laurent.pinchart, dmitry.baryshkov, quic_jesszhan,
	quic_aravindh

Add an API to reset the encoder related hw blocks to ensure
a proper teardown of the pipeline. At the moment this is being
used only for the writeback encoder but eventually we can start
using this for all interfaces.

changes in v4:
	- none

Signed-off-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c      | 85 +++++++++++++++++++++++-
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h |  7 ++
 2 files changed, 91 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 4523693..25c7eda 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -1,7 +1,9 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2014-2018, 2020-2021 The Linux Foundation. All rights reserved.
  * Copyright (C) 2013 Red Hat
+ * Copyright (c) 2014-2018, 2020-2021 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ *
  * Author: Rob Clark <robdclark@gmail.com>
  */
 
@@ -22,6 +24,7 @@
 #include "dpu_hw_ctl.h"
 #include "dpu_hw_dspp.h"
 #include "dpu_hw_dsc.h"
+#include "dpu_hw_merge3d.h"
 #include "dpu_formats.h"
 #include "dpu_encoder_phys.h"
 #include "dpu_crtc.h"
@@ -1838,6 +1841,86 @@ void dpu_encoder_kickoff(struct drm_encoder *drm_enc)
 	DPU_ATRACE_END("encoder_kickoff");
 }
 
+static void dpu_encoder_helper_reset_mixers(struct dpu_encoder_phys *phys_enc)
+{
+	struct dpu_hw_mixer_cfg mixer;
+	int i, num_lm;
+	u32 flush_mask = 0;
+	struct dpu_global_state *global_state;
+	struct dpu_hw_blk *hw_lm[2];
+	struct dpu_hw_mixer *hw_mixer[2];
+	struct dpu_hw_ctl *ctl = phys_enc->hw_ctl;
+
+	memset(&mixer, 0, sizeof(mixer));
+
+	/* reset all mixers for this encoder */
+	if (phys_enc->hw_ctl->ops.clear_all_blendstages)
+		phys_enc->hw_ctl->ops.clear_all_blendstages(phys_enc->hw_ctl);
+
+	global_state = dpu_kms_get_existing_global_state(phys_enc->dpu_kms);
+
+	num_lm = dpu_rm_get_assigned_resources(&phys_enc->dpu_kms->rm, global_state,
+		phys_enc->parent->base.id, DPU_HW_BLK_LM, hw_lm, ARRAY_SIZE(hw_lm));
+
+	for (i = 0; i < num_lm; i++) {
+		hw_mixer[i] = to_dpu_hw_mixer(hw_lm[i]);
+		flush_mask = phys_enc->hw_ctl->ops.get_bitmask_mixer(ctl, hw_mixer[i]->idx);
+		if (phys_enc->hw_ctl->ops.update_pending_flush)
+			phys_enc->hw_ctl->ops.update_pending_flush(ctl, flush_mask);
+
+		/* clear all blendstages */
+		if (phys_enc->hw_ctl->ops.setup_blendstage)
+			phys_enc->hw_ctl->ops.setup_blendstage(ctl, hw_mixer[i]->idx, NULL);
+	}
+}
+
+void dpu_encoder_helper_phys_cleanup(struct dpu_encoder_phys *phys_enc)
+{
+	struct dpu_hw_ctl *ctl = phys_enc->hw_ctl;
+	struct dpu_hw_intf_cfg intf_cfg = { 0 };
+	int i;
+	struct dpu_encoder_virt *dpu_enc;
+
+	dpu_enc = to_dpu_encoder_virt(phys_enc->parent);
+
+	phys_enc->hw_ctl->ops.reset(ctl);
+
+	dpu_encoder_helper_reset_mixers(phys_enc);
+
+	for (i = 0; i < dpu_enc->num_phys_encs; i++) {
+		if (dpu_enc->phys_encs[i] && phys_enc->hw_intf->ops.bind_pingpong_blk)
+			phys_enc->hw_intf->ops.bind_pingpong_blk(
+					dpu_enc->phys_encs[i]->hw_intf, false,
+					dpu_enc->phys_encs[i]->hw_pp->idx);
+
+		/* mark INTF flush as pending */
+		if (phys_enc->hw_ctl->ops.update_pending_flush_intf)
+			phys_enc->hw_ctl->ops.update_pending_flush_intf(phys_enc->hw_ctl,
+					dpu_enc->phys_encs[i]->hw_intf->idx);
+	}
+
+	/* reset the merge 3D HW block */
+	if (phys_enc->hw_pp->merge_3d) {
+		phys_enc->hw_pp->merge_3d->ops.setup_3d_mode(phys_enc->hw_pp->merge_3d,
+				BLEND_3D_NONE);
+		if (phys_enc->hw_ctl->ops.update_pending_flush_merge_3d)
+			phys_enc->hw_ctl->ops.update_pending_flush_merge_3d(ctl,
+					phys_enc->hw_pp->merge_3d->idx);
+	}
+
+	intf_cfg.stream_sel = 0; /* Don't care value for video mode */
+	intf_cfg.mode_3d = dpu_encoder_helper_get_3d_blend_mode(phys_enc);
+	if (phys_enc->hw_pp->merge_3d)
+		intf_cfg.merge_3d = phys_enc->hw_pp->merge_3d->idx;
+
+	if (ctl->ops.reset_intf_cfg)
+		ctl->ops.reset_intf_cfg(ctl, &intf_cfg);
+
+	ctl->ops.trigger_flush(ctl);
+	ctl->ops.trigger_start(ctl);
+	ctl->ops.clear_pending_flush(ctl);
+}
+
 void dpu_encoder_prepare_commit(struct drm_encoder *drm_enc)
 {
 	struct dpu_encoder_virt *dpu_enc;
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
index 706b566..544a9a4 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
@@ -1,5 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  * Copyright (c) 2015-2018 The Linux Foundation. All rights reserved.
  */
 
@@ -350,4 +351,10 @@ int dpu_encoder_helper_wait_for_irq(struct dpu_encoder_phys *phys_enc,
 		void (*func)(void *arg, int irq_idx),
 		struct dpu_encoder_wait_info *wait_info);
 
+/**
+ * dpu_encoder_helper_phys_cleanup - helper to cleanup dpu pipeline
+ * @phys_enc: Pointer to physical encoder structure
+ */
+void dpu_encoder_helper_phys_cleanup(struct dpu_encoder_phys *phys_enc);
+
 #endif /* __dpu_encoder_phys_H__ */
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v5 10/19] drm/msm/dpu: make changes to dpu_encoder to support virtual encoder
  2022-04-25  0:31 [PATCH v5 00/19] Add writeback block support for DPU Abhinav Kumar
                   ` (8 preceding siblings ...)
  2022-04-25  0:32 ` [PATCH v5 09/19] drm/msm/dpu: add an API to reset the encoder related hw blocks Abhinav Kumar
@ 2022-04-25  0:32 ` Abhinav Kumar
  2022-04-26  0:21   ` Dmitry Baryshkov
  2022-04-25  0:32 ` [PATCH v5 11/19] drm/msm/dpu: add encoder operations to prepare/cleanup wb job Abhinav Kumar
                   ` (8 subsequent siblings)
  18 siblings, 1 reply; 29+ messages in thread
From: Abhinav Kumar @ 2022-04-25  0:32 UTC (permalink / raw)
  To: freedreno
  Cc: markyacoub, liviu.dudau, Abhinav Kumar, dri-devel, swboyd,
	seanpaul, laurent.pinchart, dmitry.baryshkov, quic_jesszhan,
	quic_aravindh

Make changes to dpu_encoder to support virtual encoder needed
to support writeback for dpu.

changes in v4:
	- squash dpu_encoder pieces from [1]

[1] https://patchwork.freedesktop.org/patch/483099/?series=102964&rev=2

Signed-off-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c      | 94 +++++++++++++++++++-----
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h |  7 ++
 2 files changed, 83 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 25c7eda..d1e92d89 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -1013,9 +1013,18 @@ static void dpu_encoder_virt_atomic_mode_set(struct drm_encoder *drm_enc,
 		if (phys->intf_idx >= INTF_0 && phys->intf_idx < INTF_MAX)
 			phys->hw_intf = dpu_rm_get_intf(&dpu_kms->rm, phys->intf_idx);
 
-		if (!phys->hw_intf) {
+		if (phys->wb_idx >= WB_0 && phys->wb_idx < WB_MAX)
+			phys->hw_wb = dpu_rm_get_wb(&dpu_kms->rm, phys->wb_idx);
+
+		if (!phys->hw_intf && !phys->hw_wb) {
 			DPU_ERROR_ENC(dpu_enc,
-				      "no intf block assigned at idx: %d\n", i);
+				      "no intf or wb block assigned at idx: %d\n", i);
+			return;
+		}
+
+		if (phys->hw_intf && phys->hw_wb) {
+			DPU_ERROR_ENC(dpu_enc,
+					"invalid phys both intf and wb block at idx: %d\n", i);
 			return;
 		}
 
@@ -1163,16 +1172,35 @@ static enum dpu_intf dpu_encoder_get_intf(struct dpu_mdss_cfg *catalog,
 {
 	int i = 0;
 
-	for (i = 0; i < catalog->intf_count; i++) {
-		if (catalog->intf[i].type == type
-		    && catalog->intf[i].controller_id == controller_id) {
-			return catalog->intf[i].id;
+	if (type != INTF_WB) {
+		for (i = 0; i < catalog->intf_count; i++) {
+			if (catalog->intf[i].type == type
+				&& catalog->intf[i].controller_id == controller_id) {
+				return catalog->intf[i].id;
+			}
 		}
 	}
 
 	return INTF_MAX;
 }
 
+static enum dpu_wb dpu_encoder_get_wb(struct dpu_mdss_cfg *catalog,
+		enum dpu_intf_type type, u32 controller_id)
+{
+	int i = 0;
+
+	if (type != INTF_WB)
+		goto end;
+
+	for (i = 0; i < catalog->wb_count; i++) {
+		if (catalog->wb[i].id == controller_id)
+			return catalog->wb[i].id;
+	}
+
+end:
+	return WB_MAX;
+}
+
 static void dpu_encoder_vblank_callback(struct drm_encoder *drm_enc,
 		struct dpu_encoder_phys *phy_enc)
 {
@@ -1887,16 +1915,32 @@ void dpu_encoder_helper_phys_cleanup(struct dpu_encoder_phys *phys_enc)
 
 	dpu_encoder_helper_reset_mixers(phys_enc);
 
-	for (i = 0; i < dpu_enc->num_phys_encs; i++) {
-		if (dpu_enc->phys_encs[i] && phys_enc->hw_intf->ops.bind_pingpong_blk)
-			phys_enc->hw_intf->ops.bind_pingpong_blk(
-					dpu_enc->phys_encs[i]->hw_intf, false,
-					dpu_enc->phys_encs[i]->hw_pp->idx);
-
-		/* mark INTF flush as pending */
-		if (phys_enc->hw_ctl->ops.update_pending_flush_intf)
-			phys_enc->hw_ctl->ops.update_pending_flush_intf(phys_enc->hw_ctl,
-					dpu_enc->phys_encs[i]->hw_intf->idx);
+	/*
+	 * TODO: move the once-only operation like CTL flush/trigger
+	 * into dpu_encoder_virt_disable() and all operations which need
+	 * to be done per phys encoder into the phys_disable() op.
+	 */
+	if (phys_enc->hw_wb) {
+		/* disable the PP block */
+		if (phys_enc->hw_wb->ops.bind_pingpong_blk)
+			phys_enc->hw_wb->ops.bind_pingpong_blk(phys_enc->hw_wb, false,
+					phys_enc->hw_pp->idx);
+
+		/* mark WB flush as pending */
+		if (phys_enc->hw_ctl->ops.update_pending_flush_wb)
+			phys_enc->hw_ctl->ops.update_pending_flush_wb(ctl, phys_enc->hw_wb->idx);
+	} else {
+		for (i = 0; i < dpu_enc->num_phys_encs; i++) {
+			if (dpu_enc->phys_encs[i] && phys_enc->hw_intf->ops.bind_pingpong_blk)
+				phys_enc->hw_intf->ops.bind_pingpong_blk(
+						dpu_enc->phys_encs[i]->hw_intf, false,
+						dpu_enc->phys_encs[i]->hw_pp->idx);
+
+			/* mark INTF flush as pending */
+			if (phys_enc->hw_ctl->ops.update_pending_flush_intf)
+				phys_enc->hw_ctl->ops.update_pending_flush_intf(phys_enc->hw_ctl,
+						dpu_enc->phys_encs[i]->hw_intf->idx);
+		}
 	}
 
 	/* reset the merge 3D HW block */
@@ -2112,6 +2156,9 @@ static int dpu_encoder_setup_display(struct dpu_encoder_virt *dpu_enc,
 	case DRM_MODE_ENCODER_TMDS:
 		intf_type = INTF_DP;
 		break;
+	case DRM_MODE_ENCODER_VIRTUAL:
+		intf_type = INTF_WB;
+		break;
 	}
 
 	WARN_ON(disp_info->num_of_h_tiles < 1);
@@ -2149,8 +2196,19 @@ static int dpu_encoder_setup_display(struct dpu_encoder_virt *dpu_enc,
 		phys_params.intf_idx = dpu_encoder_get_intf(dpu_kms->catalog,
 													intf_type,
 													controller_id);
-		if (phys_params.intf_idx == INTF_MAX) {
-			DPU_ERROR_ENC(dpu_enc, "could not get intf: type %d, id %d\n",
+
+		phys_params.wb_idx = dpu_encoder_get_wb(dpu_kms->catalog,
+				intf_type, controller_id);
+		/*
+		 * For boards which have no physical displays, having no interface
+		 * is fine because it can still be used with just writeback.
+		 * If we try without a display on a board which uses a DPU in which
+		 * writeback is not supported, then this will still fail as it will not
+		 * find any writeback in the catalog.
+		 */
+		if ((phys_params.intf_idx == INTF_MAX) &&
+				(phys_params.wb_idx == WB_MAX)) {
+			DPU_ERROR_ENC(dpu_enc, "could not get intf or wb: type %d, id %d\n",
 						  intf_type, controller_id);
 			ret = -EINVAL;
 		}
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
index 544a9a4..c84b8e8 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
@@ -11,6 +11,7 @@
 
 #include "dpu_kms.h"
 #include "dpu_hw_intf.h"
+#include "dpu_hw_wb.h"
 #include "dpu_hw_pingpong.h"
 #include "dpu_hw_ctl.h"
 #include "dpu_hw_top.h"
@@ -165,12 +166,14 @@ enum dpu_intr_idx {
  * @hw_ctl:		Hardware interface to the ctl registers
  * @hw_pp:		Hardware interface to the ping pong registers
  * @hw_intf:		Hardware interface to the intf registers
+ * @hw_wb:		Hardware interface to the wb registers
  * @dpu_kms:		Pointer to the dpu_kms top level
  * @cached_mode:	DRM mode cached at mode_set time, acted on in enable
  * @enabled:		Whether the encoder has enabled and running a mode
  * @split_role:		Role to play in a split-panel configuration
  * @intf_mode:		Interface mode
  * @intf_idx:		Interface index on dpu hardware
+ * @wb_idx:			Writeback index on dpu hardware
  * @enc_spinlock:	Virtual-Encoder-Wide Spin Lock for IRQ purposes
  * @enable_state:	Enable state tracking
  * @vblank_refcount:	Reference count of vblank request
@@ -193,11 +196,13 @@ struct dpu_encoder_phys {
 	struct dpu_hw_ctl *hw_ctl;
 	struct dpu_hw_pingpong *hw_pp;
 	struct dpu_hw_intf *hw_intf;
+	struct dpu_hw_wb *hw_wb;
 	struct dpu_kms *dpu_kms;
 	struct drm_display_mode cached_mode;
 	enum dpu_enc_split_role split_role;
 	enum dpu_intf_mode intf_mode;
 	enum dpu_intf intf_idx;
+	enum dpu_wb wb_idx;
 	spinlock_t *enc_spinlock;
 	enum dpu_enc_enable_state enable_state;
 	atomic_t vblank_refcount;
@@ -243,6 +248,7 @@ struct dpu_encoder_phys_cmd {
  * @parent_ops:		Callbacks exposed by the parent to the phys_enc
  * @split_role:		Role to play in a split-panel configuration
  * @intf_idx:		Interface index this phys_enc will control
+ * @wb_idx:			Writeback index this phys_enc will control
  * @enc_spinlock:	Virtual-Encoder-Wide Spin Lock for IRQ purposes
  */
 struct dpu_enc_phys_init_params {
@@ -251,6 +257,7 @@ struct dpu_enc_phys_init_params {
 	const struct dpu_encoder_virt_ops *parent_ops;
 	enum dpu_enc_split_role split_role;
 	enum dpu_intf intf_idx;
+	enum dpu_wb wb_idx;
 	spinlock_t *enc_spinlock;
 };
 
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v5 11/19] drm/msm/dpu: add encoder operations to prepare/cleanup wb job
  2022-04-25  0:31 [PATCH v5 00/19] Add writeback block support for DPU Abhinav Kumar
                   ` (9 preceding siblings ...)
  2022-04-25  0:32 ` [PATCH v5 10/19] drm/msm/dpu: make changes to dpu_encoder to support virtual encoder Abhinav Kumar
@ 2022-04-25  0:32 ` Abhinav Kumar
  2022-04-25  0:32 ` [PATCH v5 12/19] drm/msm/dpu: move _dpu_plane_get_qos_lut to dpu_hw_util file Abhinav Kumar
                   ` (7 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: Abhinav Kumar @ 2022-04-25  0:32 UTC (permalink / raw)
  To: freedreno
  Cc: markyacoub, liviu.dudau, Abhinav Kumar, dri-devel, swboyd,
	seanpaul, laurent.pinchart, dmitry.baryshkov, quic_jesszhan,
	quic_aravindh

add dpu encoder APIs to prepare and cleanup writeback job
for the writeback encoder. These shall be invoked from the
prepare_wb_job/cleanup_wb_job hooks of the drm_writeback
framework.

changes in v3:
	- none

Signed-off-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c      | 34 ++++++++++++++++++++++++
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h      | 16 +++++++++++
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h |  5 ++++
 3 files changed, 55 insertions(+)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index d1e92d89..24870eb 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -913,6 +913,40 @@ static int dpu_encoder_resource_control(struct drm_encoder *drm_enc,
 	return 0;
 }
 
+void dpu_encoder_prepare_wb_job(struct drm_encoder *drm_enc,
+		struct drm_writeback_job *job)
+{
+	struct dpu_encoder_virt *dpu_enc;
+	int i;
+
+	dpu_enc = to_dpu_encoder_virt(drm_enc);
+
+	for (i = 0; i < dpu_enc->num_phys_encs; i++) {
+		struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i];
+
+		if (phys->ops.prepare_wb_job)
+			phys->ops.prepare_wb_job(phys, job);
+
+	}
+}
+
+void dpu_encoder_cleanup_wb_job(struct drm_encoder *drm_enc,
+		struct drm_writeback_job *job)
+{
+	struct dpu_encoder_virt *dpu_enc;
+	int i;
+
+	dpu_enc = to_dpu_encoder_virt(drm_enc);
+
+	for (i = 0; i < dpu_enc->num_phys_encs; i++) {
+		struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i];
+
+		if (phys->ops.cleanup_wb_job)
+			phys->ops.cleanup_wb_job(phys, job);
+
+	}
+}
+
 static void dpu_encoder_virt_atomic_mode_set(struct drm_encoder *drm_enc,
 					     struct drm_crtc_state *crtc_state,
 					     struct drm_connector_state *conn_state)
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
index 2903e65..6ceec1d 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
@@ -180,4 +180,20 @@ bool dpu_encoder_is_widebus_enabled(const struct drm_encoder *drm_enc);
  */
 bool dpu_encoder_use_dsc_merge(struct drm_encoder *drm_enc);
 
+/**
+ * dpu_encoder_prepare_wb_job - prepare writeback job for the encoder.
+ * @drm_enc:    Pointer to previously created drm encoder structure
+ * @job:        Pointer to the current drm writeback job
+ */
+void dpu_encoder_prepare_wb_job(struct drm_encoder *drm_enc,
+		struct drm_writeback_job *job);
+
+/**
+ * dpu_encoder_cleanup_wb_job - cleanup writeback job for the encoder.
+ * @drm_enc:    Pointer to previously created drm encoder structure
+ * @job:        Pointer to the current drm writeback job
+ */
+void dpu_encoder_cleanup_wb_job(struct drm_encoder *drm_enc,
+		struct drm_writeback_job *job);
+
 #endif /* __DPU_ENCODER_H__ */
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
index c84b8e8..a42ed4b 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
@@ -7,6 +7,7 @@
 #ifndef __DPU_ENCODER_PHYS_H__
 #define __DPU_ENCODER_PHYS_H__
 
+#include <drm/drm_writeback.h>
 #include <linux/jiffies.h>
 
 #include "dpu_kms.h"
@@ -137,6 +138,10 @@ struct dpu_encoder_phys_ops {
 	void (*restore)(struct dpu_encoder_phys *phys);
 	int (*get_line_count)(struct dpu_encoder_phys *phys);
 	int (*get_frame_count)(struct dpu_encoder_phys *phys);
+	void (*prepare_wb_job)(struct dpu_encoder_phys *phys_enc,
+			struct drm_writeback_job *job);
+	void (*cleanup_wb_job)(struct dpu_encoder_phys *phys_enc,
+			struct drm_writeback_job *job);
 };
 
 /**
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v5 12/19] drm/msm/dpu: move _dpu_plane_get_qos_lut to dpu_hw_util file
  2022-04-25  0:31 [PATCH v5 00/19] Add writeback block support for DPU Abhinav Kumar
                   ` (10 preceding siblings ...)
  2022-04-25  0:32 ` [PATCH v5 11/19] drm/msm/dpu: add encoder operations to prepare/cleanup wb job Abhinav Kumar
@ 2022-04-25  0:32 ` Abhinav Kumar
  2022-04-25  0:32 ` [PATCH v5 13/19] drm/msm/dpu: introduce the dpu_encoder_phys_* for writeback Abhinav Kumar
                   ` (6 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: Abhinav Kumar @ 2022-04-25  0:32 UTC (permalink / raw)
  To: freedreno
  Cc: markyacoub, liviu.dudau, Abhinav Kumar, dri-devel, swboyd,
	seanpaul, laurent.pinchart, dmitry.baryshkov, quic_jesszhan,
	quic_aravindh

_dpu_plane_get_qos_lut() is not specific to just dpu_plane.
It can take any fill level and return the LUT matching it.
This can be used even for other modules like dpu_writeback.

Move _dpu_plane_get_qos_lut() to the common dpu_hw_util file
and rename it to _dpu_hw_get_qos_lut().

Signed-off-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c | 25 +++++++++++++++++++++++++
 drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h |  4 ++++
 drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c   | 27 +--------------------------
 3 files changed, 30 insertions(+), 26 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c
index aad8511..512316f 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c
@@ -422,3 +422,28 @@ void dpu_hw_csc_setup(struct dpu_hw_blk_reg_map *c,
 	DPU_REG_WRITE(c, csc_reg_off + 0x3c, data->csc_post_bv[1]);
 	DPU_REG_WRITE(c, csc_reg_off + 0x40, data->csc_post_bv[2]);
 }
+
+/**
+ * _dpu_hw_get_qos_lut - get LUT mapping based on fill level
+ * @tbl:		Pointer to LUT table
+ * @total_fl:		fill level
+ * Return: LUT setting corresponding to the fill level
+ */
+u64 _dpu_hw_get_qos_lut(const struct dpu_qos_lut_tbl *tbl,
+		u32 total_fl)
+{
+	int i;
+
+	if (!tbl || !tbl->nentry || !tbl->entries)
+		return 0;
+
+	for (i = 0; i < tbl->nentry; i++)
+		if (total_fl <= tbl->entries[i].fl)
+			return tbl->entries[i].lut;
+
+	/* if last fl is zero, use as default */
+	if (!tbl->entries[i-1].fl)
+		return tbl->entries[i-1].lut;
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h
index a200df1..e4a65eb 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h
@@ -9,6 +9,7 @@
 #include <linux/io.h>
 #include <linux/slab.h>
 #include "dpu_hw_mdss.h"
+#include "dpu_hw_catalog.h"
 
 #define REG_MASK(n)                     ((BIT(n)) - 1)
 
@@ -339,4 +340,7 @@ void dpu_hw_csc_setup(struct dpu_hw_blk_reg_map  *c,
 		u32 csc_reg_off,
 		const struct dpu_csc_cfg *data, bool csc10);
 
+u64 _dpu_hw_get_qos_lut(const struct dpu_qos_lut_tbl *tbl,
+		u32 total_fl);
+
 #endif /* _DPU_HW_UTIL_H */
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
index 08b8c64..9d2f036 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
@@ -280,31 +280,6 @@ static int _dpu_plane_calc_fill_level(struct drm_plane *plane,
 }
 
 /**
- * _dpu_plane_get_qos_lut - get LUT mapping based on fill level
- * @tbl:		Pointer to LUT table
- * @total_fl:		fill level
- * Return: LUT setting corresponding to the fill level
- */
-static u64 _dpu_plane_get_qos_lut(const struct dpu_qos_lut_tbl *tbl,
-		u32 total_fl)
-{
-	int i;
-
-	if (!tbl || !tbl->nentry || !tbl->entries)
-		return 0;
-
-	for (i = 0; i < tbl->nentry; i++)
-		if (total_fl <= tbl->entries[i].fl)
-			return tbl->entries[i].lut;
-
-	/* if last fl is zero, use as default */
-	if (!tbl->entries[i-1].fl)
-		return tbl->entries[i-1].lut;
-
-	return 0;
-}
-
-/**
  * _dpu_plane_set_qos_lut - set QoS LUT of the given plane
  * @plane:		Pointer to drm plane
  * @fb:			Pointer to framebuffer associated with the given plane
@@ -333,7 +308,7 @@ static void _dpu_plane_set_qos_lut(struct drm_plane *plane,
 			lut_usage = DPU_QOS_LUT_USAGE_MACROTILE;
 	}
 
-	qos_lut = _dpu_plane_get_qos_lut(
+	qos_lut = _dpu_hw_get_qos_lut(
 			&pdpu->catalog->perf.qos_lut_tbl[lut_usage], total_fl);
 
 	trace_dpu_perf_set_qos_luts(pdpu->pipe - SSPP_VIG0,
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v5 13/19] drm/msm/dpu: introduce the dpu_encoder_phys_* for writeback
  2022-04-25  0:31 [PATCH v5 00/19] Add writeback block support for DPU Abhinav Kumar
                   ` (11 preceding siblings ...)
  2022-04-25  0:32 ` [PATCH v5 12/19] drm/msm/dpu: move _dpu_plane_get_qos_lut to dpu_hw_util file Abhinav Kumar
@ 2022-04-25  0:32 ` Abhinav Kumar
  2022-04-25  0:32 ` [PATCH v5 14/19] drm/msm/dpu: add the writeback connector layer Abhinav Kumar
                   ` (5 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: Abhinav Kumar @ 2022-04-25  0:32 UTC (permalink / raw)
  To: freedreno
  Cc: markyacoub, liviu.dudau, Abhinav Kumar, dri-devel, swboyd,
	seanpaul, laurent.pinchart, dmitry.baryshkov, quic_jesszhan,
	quic_aravindh

Introduce the dpu_encoder_phys_* for the writeback interface
to handle writeback specific hardware programming.

changes in v4:
	- squash the encoder_phys_wb bits from [1]
	- since its a trivial change of a previously acked change
	  preserving the ack

[1] https://patchwork.freedesktop.org/patch/483099/?series=102964&rev=2

Signed-off-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
 drivers/gpu/drm/msm/Makefile                       |   1 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h   |  30 +
 .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c    | 751 +++++++++++++++++++++
 3 files changed, 782 insertions(+)
 create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c

diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index ca779c1..0387f22 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -60,6 +60,7 @@ msm-$(CONFIG_DRM_MSM_DPU) += \
 	disp/dpu1/dpu_encoder.o \
 	disp/dpu1/dpu_encoder_phys_cmd.o \
 	disp/dpu1/dpu_encoder_phys_vid.o \
+	disp/dpu1/dpu_encoder_phys_wb.o \
 	disp/dpu1/dpu_formats.o \
 	disp/dpu1/dpu_hw_catalog.o \
 	disp/dpu1/dpu_hw_ctl.o \
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
index a42ed4b..bed4523 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
@@ -150,6 +150,7 @@ struct dpu_encoder_phys_ops {
  * @INTR_IDX_PINGPONG: Pingpong done unterrupt for cmd mode panel
  * @INTR_IDX_UNDERRUN: Underrun unterrupt for video and cmd mode panel
  * @INTR_IDX_RDPTR:    Readpointer done unterrupt for cmd mode panel
+ * @INTR_IDX_WB_DONE:  Writeback fone interrupt for virtual connector
  */
 enum dpu_intr_idx {
 	INTR_IDX_VSYNC,
@@ -157,6 +158,7 @@ enum dpu_intr_idx {
 	INTR_IDX_UNDERRUN,
 	INTR_IDX_CTL_START,
 	INTR_IDX_RDPTR,
+	INTR_IDX_WB_DONE,
 	INTR_IDX_MAX,
 };
 
@@ -226,6 +228,27 @@ static inline int dpu_encoder_phys_inc_pending(struct dpu_encoder_phys *phys)
 }
 
 /**
+ * struct dpu_encoder_phys_wb - sub-class of dpu_encoder_phys to handle command
+ *	mode specific operations
+ * @base:	Baseclass physical encoder structure
+ * @wbirq_refcount:     Reference count of writeback interrupt
+ * @wb_done_timeout_cnt: number of wb done irq timeout errors
+ * @wb_cfg:  writeback block config to store fb related details
+ * @wb_conn: backpointer to writeback connector
+ * @wb_job: backpointer to current writeback job
+ * @dest:   dpu buffer layout for current writeback output buffer
+ */
+struct dpu_encoder_phys_wb {
+	struct dpu_encoder_phys base;
+	atomic_t wbirq_refcount;
+	int wb_done_timeout_cnt;
+	struct dpu_hw_wb_cfg wb_cfg;
+	struct drm_writeback_connector *wb_conn;
+	struct drm_writeback_job *wb_job;
+	struct dpu_hw_fmt_layout dest;
+};
+
+/**
  * struct dpu_encoder_phys_cmd - sub-class of dpu_encoder_phys to handle command
  *	mode specific operations
  * @base:	Baseclass physical encoder structure
@@ -295,6 +318,13 @@ struct dpu_encoder_phys *dpu_encoder_phys_cmd_init(
 		struct dpu_enc_phys_init_params *p);
 
 /**
+ * dpu_encoder_phys_wb_init - initialize writeback encoder
+ * @init:	Pointer to init info structure with initialization params
+ */
+struct dpu_encoder_phys *dpu_encoder_phys_wb_init(
+		struct dpu_enc_phys_init_params *p);
+
+/**
  * dpu_encoder_helper_trigger_start - control start helper function
  *	This helper function may be optionally specified by physical
  *	encoders if they require ctl_start triggering.
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
new file mode 100644
index 0000000..4ab2699
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
@@ -0,0 +1,751 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#define pr_fmt(fmt)	"[drm:%s:%d] " fmt, __func__, __LINE__
+
+#include <linux/debugfs.h>
+
+#include "dpu_encoder_phys.h"
+#include "dpu_formats.h"
+#include "dpu_hw_top.h"
+#include "dpu_hw_wb.h"
+#include "dpu_hw_lm.h"
+#include "dpu_hw_blk.h"
+#include "dpu_hw_merge3d.h"
+#include "dpu_hw_interrupts.h"
+#include "dpu_core_irq.h"
+#include "dpu_vbif.h"
+#include "dpu_crtc.h"
+#include "disp/msm_disp_snapshot.h"
+
+#define DEFAULT_MAX_WRITEBACK_WIDTH 2048
+
+#define to_dpu_encoder_phys_wb(x) \
+	container_of(x, struct dpu_encoder_phys_wb, base)
+
+/**
+ * dpu_encoder_phys_wb_is_master - report wb always as master encoder
+ */
+static bool dpu_encoder_phys_wb_is_master(struct dpu_encoder_phys *phys_enc)
+{
+	/* there is only one physical enc for dpu_writeback */
+	return true;
+}
+
+/**
+ * dpu_encoder_phys_wb_set_ot_limit - set OT limit for writeback interface
+ * @phys_enc:	Pointer to physical encoder
+ */
+static void dpu_encoder_phys_wb_set_ot_limit(
+		struct dpu_encoder_phys *phys_enc)
+{
+	struct dpu_hw_wb *hw_wb = phys_enc->hw_wb;
+	struct dpu_vbif_set_ot_params ot_params;
+
+	memset(&ot_params, 0, sizeof(ot_params));
+	ot_params.xin_id = hw_wb->caps->xin_id;
+	ot_params.num = hw_wb->idx - WB_0;
+	ot_params.width = phys_enc->cached_mode.hdisplay;
+	ot_params.height = phys_enc->cached_mode.vdisplay;
+	ot_params.is_wfd = true;
+	ot_params.frame_rate = drm_mode_vrefresh(&phys_enc->cached_mode);
+	ot_params.vbif_idx = hw_wb->caps->vbif_idx;
+	ot_params.clk_ctrl = hw_wb->caps->clk_ctrl;
+	ot_params.rd = false;
+
+	dpu_vbif_set_ot_limit(phys_enc->dpu_kms, &ot_params);
+}
+
+/**
+ * dpu_encoder_phys_wb_set_qos_remap - set QoS remapper for writeback
+ * @phys_enc:	Pointer to physical encoder
+ */
+static void dpu_encoder_phys_wb_set_qos_remap(
+		struct dpu_encoder_phys *phys_enc)
+{
+	struct dpu_hw_wb *hw_wb;
+	struct dpu_vbif_set_qos_params qos_params;
+
+	if (!phys_enc || !phys_enc->parent || !phys_enc->parent->crtc) {
+		DPU_ERROR("invalid arguments\n");
+		return;
+	}
+
+	if (!phys_enc->hw_wb || !phys_enc->hw_wb->caps) {
+		DPU_ERROR("invalid writeback hardware\n");
+		return;
+	}
+
+	hw_wb = phys_enc->hw_wb;
+
+	memset(&qos_params, 0, sizeof(qos_params));
+	qos_params.vbif_idx = hw_wb->caps->vbif_idx;
+	qos_params.xin_id = hw_wb->caps->xin_id;
+	qos_params.clk_ctrl = hw_wb->caps->clk_ctrl;
+	qos_params.num = hw_wb->idx - WB_0;
+	qos_params.is_rt = false;
+
+	DPU_DEBUG("[qos_remap] wb:%d vbif:%d xin:%d is_rt:%d\n",
+			qos_params.num,
+			qos_params.vbif_idx,
+			qos_params.xin_id, qos_params.is_rt);
+
+	dpu_vbif_set_qos_remap(phys_enc->dpu_kms, &qos_params);
+}
+
+/**
+ * dpu_encoder_phys_wb_set_qos - set QoS/danger/safe LUTs for writeback
+ * @phys_enc:	Pointer to physical encoder
+ */
+static void dpu_encoder_phys_wb_set_qos(struct dpu_encoder_phys *phys_enc)
+{
+	struct dpu_hw_wb *hw_wb;
+	struct dpu_hw_wb_qos_cfg qos_cfg;
+	struct dpu_mdss_cfg *catalog;
+	struct dpu_qos_lut_tbl *qos_lut_tb;
+
+	if (!phys_enc || !phys_enc->dpu_kms || !phys_enc->dpu_kms->catalog) {
+		DPU_ERROR("invalid parameter(s)\n");
+		return;
+	}
+
+	catalog = phys_enc->dpu_kms->catalog;
+
+	hw_wb = phys_enc->hw_wb;
+
+	memset(&qos_cfg, 0, sizeof(struct dpu_hw_wb_qos_cfg));
+	qos_cfg.danger_safe_en = true;
+	qos_cfg.danger_lut =
+		catalog->perf.danger_lut_tbl[DPU_QOS_LUT_USAGE_NRT];
+
+	qos_cfg.safe_lut = catalog->perf.safe_lut_tbl[DPU_QOS_LUT_USAGE_NRT];
+
+	qos_lut_tb = &catalog->perf.qos_lut_tbl[DPU_QOS_LUT_USAGE_NRT];
+	qos_cfg.creq_lut = _dpu_hw_get_qos_lut(qos_lut_tb, 0);
+
+	if (hw_wb->ops.setup_qos_lut)
+		hw_wb->ops.setup_qos_lut(hw_wb, &qos_cfg);
+}
+
+/**
+ * dpu_encoder_phys_wb_setup_fb - setup output framebuffer
+ * @phys_enc:	Pointer to physical encoder
+ * @fb:		Pointer to output framebuffer
+ * @wb_roi:	Pointer to output region of interest
+ */
+static void dpu_encoder_phys_wb_setup_fb(struct dpu_encoder_phys *phys_enc,
+		struct drm_framebuffer *fb)
+{
+	struct dpu_encoder_phys_wb *wb_enc = to_dpu_encoder_phys_wb(phys_enc);
+	struct dpu_hw_wb *hw_wb;
+	struct dpu_hw_wb_cfg *wb_cfg;
+	struct dpu_hw_cdp_cfg cdp_cfg;
+
+	if (!phys_enc || !phys_enc->dpu_kms || !phys_enc->dpu_kms->catalog) {
+		DPU_ERROR("invalid encoder\n");
+		return;
+	}
+
+	hw_wb = phys_enc->hw_wb;
+	wb_cfg = &wb_enc->wb_cfg;
+
+	wb_cfg->intf_mode = phys_enc->intf_mode;
+	wb_cfg->roi.x1 = 0;
+	wb_cfg->roi.x2 = phys_enc->cached_mode.hdisplay;
+	wb_cfg->roi.y1 = 0;
+	wb_cfg->roi.y2 = phys_enc->cached_mode.vdisplay;
+
+	if (hw_wb->ops.setup_roi)
+		hw_wb->ops.setup_roi(hw_wb, wb_cfg);
+
+	if (hw_wb->ops.setup_outformat)
+		hw_wb->ops.setup_outformat(hw_wb, wb_cfg);
+
+	if (hw_wb->ops.setup_cdp) {
+		memset(&cdp_cfg, 0, sizeof(struct dpu_hw_cdp_cfg));
+
+		cdp_cfg.enable = phys_enc->dpu_kms->catalog->perf.cdp_cfg
+				[DPU_PERF_CDP_USAGE_NRT].wr_enable;
+		cdp_cfg.ubwc_meta_enable =
+				DPU_FORMAT_IS_UBWC(wb_cfg->dest.format);
+		cdp_cfg.tile_amortize_enable =
+				DPU_FORMAT_IS_UBWC(wb_cfg->dest.format) ||
+				DPU_FORMAT_IS_TILE(wb_cfg->dest.format);
+		cdp_cfg.preload_ahead = DPU_WB_CDP_PRELOAD_AHEAD_64;
+
+		hw_wb->ops.setup_cdp(hw_wb, &cdp_cfg);
+	}
+
+	if (hw_wb->ops.setup_outaddress)
+		hw_wb->ops.setup_outaddress(hw_wb, wb_cfg);
+}
+
+/**
+ * dpu_encoder_phys_wb_setup_cdp - setup chroma down prefetch block
+ * @phys_enc:Pointer to physical encoder
+ */
+static void dpu_encoder_phys_wb_setup_cdp(struct dpu_encoder_phys *phys_enc)
+{
+	struct dpu_hw_wb *hw_wb;
+	struct dpu_hw_ctl *ctl;
+
+	if (!phys_enc) {
+		DPU_ERROR("invalid encoder\n");
+		return;
+	}
+
+	hw_wb = phys_enc->hw_wb;
+	ctl = phys_enc->hw_ctl;
+
+	if (test_bit(DPU_CTL_ACTIVE_CFG, &ctl->caps->features) &&
+		(phys_enc->hw_ctl &&
+		 phys_enc->hw_ctl->ops.setup_intf_cfg)) {
+		struct dpu_hw_intf_cfg intf_cfg = {0};
+		struct dpu_hw_pingpong *hw_pp = phys_enc->hw_pp;
+		enum dpu_3d_blend_mode mode_3d;
+
+		mode_3d = dpu_encoder_helper_get_3d_blend_mode(phys_enc);
+
+		intf_cfg.intf = DPU_NONE;
+		intf_cfg.wb = hw_wb->idx;
+
+		if (mode_3d && hw_pp && hw_pp->merge_3d)
+			intf_cfg.merge_3d = hw_pp->merge_3d->idx;
+
+		if (phys_enc->hw_pp->merge_3d && phys_enc->hw_pp->merge_3d->ops.setup_3d_mode)
+			phys_enc->hw_pp->merge_3d->ops.setup_3d_mode(phys_enc->hw_pp->merge_3d,
+					mode_3d);
+
+		/* setup which pp blk will connect to this wb */
+		if (hw_pp && phys_enc->hw_wb->ops.bind_pingpong_blk)
+			phys_enc->hw_wb->ops.bind_pingpong_blk(phys_enc->hw_wb, true,
+					phys_enc->hw_pp->idx);
+
+		phys_enc->hw_ctl->ops.setup_intf_cfg(phys_enc->hw_ctl, &intf_cfg);
+	} else if (phys_enc->hw_ctl && phys_enc->hw_ctl->ops.setup_intf_cfg) {
+		struct dpu_hw_intf_cfg intf_cfg = {0};
+
+		intf_cfg.intf = DPU_NONE;
+		intf_cfg.wb = hw_wb->idx;
+		intf_cfg.mode_3d =
+			dpu_encoder_helper_get_3d_blend_mode(phys_enc);
+		phys_enc->hw_ctl->ops.setup_intf_cfg(phys_enc->hw_ctl, &intf_cfg);
+	}
+}
+
+/**
+ * dpu_encoder_phys_wb_atomic_check - verify and fixup given atomic states
+ * @phys_enc:	Pointer to physical encoder
+ * @crtc_state:	Pointer to CRTC atomic state
+ * @conn_state:	Pointer to connector atomic state
+ */
+static int dpu_encoder_phys_wb_atomic_check(
+		struct dpu_encoder_phys *phys_enc,
+		struct drm_crtc_state *crtc_state,
+		struct drm_connector_state *conn_state)
+{
+	struct drm_framebuffer *fb;
+	const struct drm_display_mode *mode;
+
+	DPU_DEBUG("[atomic_check:%d, \"%s\",%d,%d]\n",
+			phys_enc->wb_idx, mode->name, mode->hdisplay, mode->vdisplay);
+
+	if (!conn_state->writeback_job || !conn_state->writeback_job->fb)
+		return 0;
+
+	fb = conn_state->writeback_job->fb;
+	mode = &crtc_state->mode;
+
+	if (!conn_state || !conn_state->connector) {
+		DPU_ERROR("invalid connector state\n");
+		return -EINVAL;
+	} else if (conn_state->connector->status !=
+			connector_status_connected) {
+		DPU_ERROR("connector not connected %d\n",
+				conn_state->connector->status);
+		return -EINVAL;
+	}
+
+	DPU_DEBUG("[fb_id:%u][fb:%u,%u]\n", fb->base.id,
+			fb->width, fb->height);
+
+	if (fb->width != mode->hdisplay) {
+		DPU_ERROR("invalid fb w=%d, mode w=%d\n", fb->width,
+				mode->hdisplay);
+		return -EINVAL;
+	} else if (fb->height != mode->vdisplay) {
+		DPU_ERROR("invalid fb h=%d, mode h=%d\n", fb->height,
+				  mode->vdisplay);
+		return -EINVAL;
+	} else if (fb->width > DEFAULT_MAX_WRITEBACK_WIDTH) {
+		DPU_ERROR("invalid fb w=%d, maxlinewidth=%u\n",
+				  fb->width, DEFAULT_MAX_WRITEBACK_WIDTH);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+
+/**
+ * _dpu_encoder_phys_wb_update_flush - flush hardware update
+ * @phys_enc:	Pointer to physical encoder
+ */
+static void _dpu_encoder_phys_wb_update_flush(struct dpu_encoder_phys *phys_enc)
+{
+	struct dpu_hw_wb *hw_wb;
+	struct dpu_hw_ctl *hw_ctl;
+	struct dpu_hw_pingpong *hw_pp;
+	u32 pending_flush = 0;
+
+	if (!phys_enc)
+		return;
+
+	hw_wb = phys_enc->hw_wb;
+	hw_pp = phys_enc->hw_pp;
+	hw_ctl = phys_enc->hw_ctl;
+
+	DPU_DEBUG("[wb:%d]\n", hw_wb->idx - WB_0);
+
+	if (!hw_ctl) {
+		DPU_DEBUG("[wb:%d] no ctl assigned\n", hw_wb->idx - WB_0);
+		return;
+	}
+
+	if (hw_ctl->ops.update_pending_flush_wb)
+		hw_ctl->ops.update_pending_flush_wb(hw_ctl, hw_wb->idx);
+
+	if (hw_ctl->ops.update_pending_flush_merge_3d && hw_pp && hw_pp->merge_3d)
+		hw_ctl->ops.update_pending_flush_merge_3d(hw_ctl,
+				hw_pp->merge_3d->idx);
+
+	if (hw_ctl->ops.get_pending_flush)
+		pending_flush = hw_ctl->ops.get_pending_flush(hw_ctl);
+
+	DPU_DEBUG("Pending flush mask for CTL_%d is 0x%x, WB %d\n",
+			hw_ctl->idx - CTL_0, pending_flush,
+			hw_wb->idx - WB_0);
+}
+
+/**
+ * dpu_encoder_phys_wb_setup - setup writeback encoder
+ * @phys_enc:	Pointer to physical encoder
+ */
+static void dpu_encoder_phys_wb_setup(
+		struct dpu_encoder_phys *phys_enc)
+{
+	struct dpu_hw_wb *hw_wb = phys_enc->hw_wb;
+	struct drm_display_mode mode = phys_enc->cached_mode;
+	struct drm_framebuffer *fb = NULL;
+
+	DPU_DEBUG("[mode_set:%d, \"%s\",%d,%d]\n",
+			hw_wb->idx - WB_0, mode.name,
+			mode.hdisplay, mode.vdisplay);
+
+	dpu_encoder_phys_wb_set_ot_limit(phys_enc);
+
+	dpu_encoder_phys_wb_set_qos_remap(phys_enc);
+
+	dpu_encoder_phys_wb_set_qos(phys_enc);
+
+	dpu_encoder_phys_wb_setup_fb(phys_enc, fb);
+
+	dpu_encoder_phys_wb_setup_cdp(phys_enc);
+
+}
+
+static void _dpu_encoder_phys_wb_frame_done_helper(void *arg)
+{
+	struct dpu_encoder_phys *phys_enc = arg;
+	struct dpu_encoder_phys_wb *wb_enc = to_dpu_encoder_phys_wb(phys_enc);
+
+	struct dpu_hw_wb *hw_wb = phys_enc->hw_wb;
+	unsigned long lock_flags;
+	u32 event = DPU_ENCODER_FRAME_EVENT_DONE;
+
+	DPU_DEBUG("[wb:%d]\n", hw_wb->idx - WB_0);
+
+	if (phys_enc->parent_ops->handle_frame_done)
+		phys_enc->parent_ops->handle_frame_done(phys_enc->parent,
+				phys_enc, event);
+
+	if (phys_enc->parent_ops->handle_vblank_virt)
+		phys_enc->parent_ops->handle_vblank_virt(phys_enc->parent,
+				phys_enc);
+
+	spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
+	atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0);
+	spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags);
+
+	if (wb_enc->wb_conn)
+		drm_writeback_signal_completion(wb_enc->wb_conn, 0);
+
+	/* Signal any waiting atomic commit thread */
+	wake_up_all(&phys_enc->pending_kickoff_wq);
+}
+
+/**
+ * dpu_encoder_phys_wb_done_irq - writeback interrupt handler
+ * @arg:	Pointer to writeback encoder
+ * @irq_idx:	interrupt index
+ */
+static void dpu_encoder_phys_wb_done_irq(void *arg, int irq_idx)
+{
+	_dpu_encoder_phys_wb_frame_done_helper(arg);
+}
+
+/**
+ * dpu_encoder_phys_wb_irq_ctrl - irq control of WB
+ * @phys:	Pointer to physical encoder
+ * @enable:	indicates enable or disable interrupts
+ */
+static void dpu_encoder_phys_wb_irq_ctrl(
+		struct dpu_encoder_phys *phys, bool enable)
+{
+
+	struct dpu_encoder_phys_wb *wb_enc = to_dpu_encoder_phys_wb(phys);
+	int ret = 0;
+	int refcount;
+
+	refcount = atomic_read(&wb_enc->wbirq_refcount);
+
+	if (enable && atomic_inc_return(&wb_enc->wbirq_refcount) == 1) {
+		dpu_core_irq_register_callback(phys->dpu_kms,
+				phys->irq[INTR_IDX_WB_DONE], dpu_encoder_phys_wb_done_irq, phys);
+		if (ret)
+			atomic_dec_return(&wb_enc->wbirq_refcount);
+	} else if (!enable &&
+			atomic_dec_return(&wb_enc->wbirq_refcount) == 0) {
+		dpu_core_irq_unregister_callback(phys->dpu_kms, phys->irq[INTR_IDX_WB_DONE]);
+		if (ret)
+			atomic_inc_return(&wb_enc->wbirq_refcount);
+	}
+}
+
+static void dpu_encoder_phys_wb_atomic_mode_set(
+		struct dpu_encoder_phys *phys_enc,
+		struct drm_crtc_state *crtc_state,
+		struct drm_connector_state *conn_state)
+{
+
+	phys_enc->irq[INTR_IDX_WB_DONE] = phys_enc->hw_wb->caps->intr_wb_done;
+}
+
+static void _dpu_encoder_phys_wb_handle_wbdone_timeout(
+		struct dpu_encoder_phys *phys_enc)
+{
+	struct dpu_encoder_phys_wb *wb_enc = to_dpu_encoder_phys_wb(phys_enc);
+	u32 frame_event = DPU_ENCODER_FRAME_EVENT_ERROR;
+
+	wb_enc->wb_done_timeout_cnt++;
+
+	if (wb_enc->wb_done_timeout_cnt == 1)
+		msm_disp_snapshot_state(phys_enc->parent->dev);
+
+	atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0);
+
+	/* request a ctl reset before the next kickoff */
+	phys_enc->enable_state = DPU_ENC_ERR_NEEDS_HW_RESET;
+
+	if (wb_enc->wb_conn)
+		drm_writeback_signal_completion(wb_enc->wb_conn, 0);
+
+	if (phys_enc->parent_ops->handle_frame_done)
+		phys_enc->parent_ops->handle_frame_done(
+				phys_enc->parent, phys_enc, frame_event);
+}
+
+/**
+ * dpu_encoder_phys_wb_wait_for_commit_done - wait until request is committed
+ * @phys_enc:	Pointer to physical encoder
+ */
+static int dpu_encoder_phys_wb_wait_for_commit_done(
+		struct dpu_encoder_phys *phys_enc)
+{
+	unsigned long ret;
+	struct dpu_encoder_wait_info wait_info;
+	struct dpu_encoder_phys_wb *wb_enc = to_dpu_encoder_phys_wb(phys_enc);
+
+	wait_info.wq = &phys_enc->pending_kickoff_wq;
+	wait_info.atomic_cnt = &phys_enc->pending_kickoff_cnt;
+	wait_info.timeout_ms = KICKOFF_TIMEOUT_MS;
+
+	ret = dpu_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_WB_DONE,
+			dpu_encoder_phys_wb_done_irq, &wait_info);
+	if (ret == -ETIMEDOUT)
+		_dpu_encoder_phys_wb_handle_wbdone_timeout(phys_enc);
+	else if (!ret)
+		wb_enc->wb_done_timeout_cnt = 0;
+
+	return ret;
+}
+
+/**
+ * dpu_encoder_phys_wb_prepare_for_kickoff - pre-kickoff processing
+ * @phys_enc:	Pointer to physical encoder
+ * Returns:	Zero on success
+ */
+static void dpu_encoder_phys_wb_prepare_for_kickoff(
+		struct dpu_encoder_phys *phys_enc)
+{
+	struct dpu_encoder_phys_wb *wb_enc = to_dpu_encoder_phys_wb(phys_enc);
+	struct drm_connector *drm_conn;
+	struct drm_connector_state *state;
+
+	DPU_DEBUG("[wb:%d]\n", phys_enc->hw_wb->idx - WB_0);
+
+	if (!wb_enc->wb_conn || !wb_enc->wb_job) {
+		DPU_ERROR("invalid wb_conn or wb_job\n");
+		return;
+	}
+
+	drm_conn = &wb_enc->wb_conn->base;
+	state = drm_conn->state;
+
+	if (wb_enc->wb_conn && wb_enc->wb_job)
+		drm_writeback_queue_job(wb_enc->wb_conn, state);
+
+	dpu_encoder_phys_wb_setup(phys_enc);
+
+	_dpu_encoder_phys_wb_update_flush(phys_enc);
+}
+
+/**
+ * dpu_encoder_phys_wb_needs_single_flush - trigger flush processing
+ * @phys_enc:	Pointer to physical encoder
+ */
+static bool dpu_encoder_phys_wb_needs_single_flush(struct dpu_encoder_phys *phys_enc)
+{
+	DPU_DEBUG("[wb:%d]\n", phys_enc->hw_wb->idx - WB_0);
+	return false;
+}
+
+/**
+ * dpu_encoder_phys_wb_handle_post_kickoff - post-kickoff processing
+ * @phys_enc:	Pointer to physical encoder
+ */
+static void dpu_encoder_phys_wb_handle_post_kickoff(
+		struct dpu_encoder_phys *phys_enc)
+{
+	DPU_DEBUG("[wb:%d]\n", phys_enc->hw_wb->idx - WB_0);
+
+}
+
+/**
+ * dpu_encoder_phys_wb_enable - enable writeback encoder
+ * @phys_enc:	Pointer to physical encoder
+ */
+static void dpu_encoder_phys_wb_enable(struct dpu_encoder_phys *phys_enc)
+{
+	DPU_DEBUG("[wb:%d]\n", phys_enc->hw_wb->idx - WB_0);
+	phys_enc->enable_state = DPU_ENC_ENABLED;
+}
+/**
+ * dpu_encoder_phys_wb_disable - disable writeback encoder
+ * @phys_enc:	Pointer to physical encoder
+ */
+static void dpu_encoder_phys_wb_disable(struct dpu_encoder_phys *phys_enc)
+{
+	struct dpu_hw_wb *hw_wb = phys_enc->hw_wb;
+	struct dpu_hw_ctl *hw_ctl = phys_enc->hw_ctl;
+
+	DPU_DEBUG("[wb:%d]\n", hw_wb->idx - WB_0);
+
+	if (phys_enc->enable_state == DPU_ENC_DISABLED) {
+		DPU_ERROR("encoder is already disabled\n");
+		return;
+	}
+
+	/* reset h/w before final flush */
+	if (phys_enc->hw_ctl->ops.clear_pending_flush)
+		phys_enc->hw_ctl->ops.clear_pending_flush(phys_enc->hw_ctl);
+
+	/*
+	 * New CTL reset sequence from 5.0 MDP onwards.
+	 * If has_3d_merge_reset is not set, legacy reset
+	 * sequence is executed.
+	 *
+	 * Legacy reset sequence has not been implemented yet.
+	 * Any target earlier than SM8150 will need it and when
+	 * WB support is added to those targets will need to add
+	 * the legacy teardown sequence as well.
+	 */
+	if (hw_ctl->caps->features & BIT(DPU_CTL_ACTIVE_CFG))
+		dpu_encoder_helper_phys_cleanup(phys_enc);
+
+	phys_enc->enable_state = DPU_ENC_DISABLED;
+}
+
+/**
+ * dpu_encoder_phys_wb_destroy - destroy writeback encoder
+ * @phys_enc:	Pointer to physical encoder
+ */
+static void dpu_encoder_phys_wb_destroy(struct dpu_encoder_phys *phys_enc)
+{
+	DPU_DEBUG("[wb:%d]\n", phys_enc->wb_idx - WB_0);
+
+	if (!phys_enc)
+		return;
+
+	kfree(phys_enc);
+}
+
+static void dpu_encoder_phys_wb_prepare_wb_job(struct dpu_encoder_phys *phys_enc,
+		struct drm_writeback_job *job)
+{
+	const struct msm_format *format;
+	struct msm_gem_address_space *aspace;
+	struct dpu_hw_wb_cfg *wb_cfg;
+	int ret;
+	struct dpu_encoder_phys_wb *wb_enc = to_dpu_encoder_phys_wb(phys_enc);
+
+	if (!job->fb)
+		return;
+
+	wb_enc->wb_job = job;
+	wb_enc->wb_conn = job->connector;
+	aspace = phys_enc->dpu_kms->base.aspace;
+
+	wb_cfg = &wb_enc->wb_cfg;
+
+	memset(wb_cfg, 0, sizeof(struct dpu_hw_wb_cfg));
+
+	ret = msm_framebuffer_prepare(job->fb, aspace, false);
+	if (ret) {
+		DPU_ERROR("prep fb failed, %d\n", ret);
+		return;
+	}
+
+	format = msm_framebuffer_format(job->fb);
+
+	wb_cfg->dest.format = dpu_get_dpu_format_ext(
+			format->pixel_format, job->fb->modifier);
+	if (!wb_cfg->dest.format) {
+		/* this error should be detected during atomic_check */
+		DPU_ERROR("failed to get format %x\n", format->pixel_format);
+		return;
+	}
+
+	ret = dpu_format_populate_layout(aspace, job->fb, &wb_cfg->dest);
+	if (ret) {
+		DPU_DEBUG("failed to populate layout %d\n", ret);
+		return;
+	}
+
+	wb_cfg->dest.width = job->fb->width;
+	wb_cfg->dest.height = job->fb->height;
+	wb_cfg->dest.num_planes = wb_cfg->dest.format->num_planes;
+
+	if ((wb_cfg->dest.format->fetch_planes == DPU_PLANE_PLANAR) &&
+			(wb_cfg->dest.format->element[0] == C1_B_Cb))
+		swap(wb_cfg->dest.plane_addr[1], wb_cfg->dest.plane_addr[2]);
+
+	DPU_DEBUG("[fb_offset:%8.8x,%8.8x,%8.8x,%8.8x]\n",
+			wb_cfg->dest.plane_addr[0], wb_cfg->dest.plane_addr[1],
+			wb_cfg->dest.plane_addr[2], wb_cfg->dest.plane_addr[3]);
+
+	DPU_DEBUG("[fb_stride:%8.8x,%8.8x,%8.8x,%8.8x]\n",
+			wb_cfg->dest.plane_pitch[0], wb_cfg->dest.plane_pitch[1],
+			wb_cfg->dest.plane_pitch[2], wb_cfg->dest.plane_pitch[3]);
+}
+
+static void dpu_encoder_phys_wb_cleanup_wb_job(struct dpu_encoder_phys *phys_enc,
+		struct drm_writeback_job *job)
+{
+	struct dpu_encoder_phys_wb *wb_enc = to_dpu_encoder_phys_wb(phys_enc);
+	struct msm_gem_address_space *aspace;
+
+	if (!job->fb)
+		return;
+
+	aspace = phys_enc->dpu_kms->base.aspace;
+
+	msm_framebuffer_cleanup(job->fb, aspace, false);
+	wb_enc->wb_job = NULL;
+	wb_enc->wb_conn = NULL;
+}
+
+/**
+ * dpu_encoder_phys_wb_init_ops - initialize writeback operations
+ * @ops:	Pointer to encoder operation table
+ */
+static void dpu_encoder_phys_wb_init_ops(struct dpu_encoder_phys_ops *ops)
+{
+	ops->is_master = dpu_encoder_phys_wb_is_master;
+	ops->atomic_mode_set = dpu_encoder_phys_wb_atomic_mode_set;
+	ops->enable = dpu_encoder_phys_wb_enable;
+	ops->disable = dpu_encoder_phys_wb_disable;
+	ops->destroy = dpu_encoder_phys_wb_destroy;
+	ops->atomic_check = dpu_encoder_phys_wb_atomic_check;
+	ops->wait_for_commit_done = dpu_encoder_phys_wb_wait_for_commit_done;
+	ops->prepare_for_kickoff = dpu_encoder_phys_wb_prepare_for_kickoff;
+	ops->handle_post_kickoff = dpu_encoder_phys_wb_handle_post_kickoff;
+	ops->needs_single_flush = dpu_encoder_phys_wb_needs_single_flush;
+	ops->trigger_start = dpu_encoder_helper_trigger_start;
+	ops->prepare_wb_job = dpu_encoder_phys_wb_prepare_wb_job;
+	ops->cleanup_wb_job = dpu_encoder_phys_wb_cleanup_wb_job;
+	ops->irq_control = dpu_encoder_phys_wb_irq_ctrl;
+}
+
+/**
+ * dpu_encoder_phys_wb_init - initialize writeback encoder
+ * @init:	Pointer to init info structure with initialization params
+ */
+struct dpu_encoder_phys *dpu_encoder_phys_wb_init(
+		struct dpu_enc_phys_init_params *p)
+{
+	struct dpu_encoder_phys *phys_enc = NULL;
+	struct dpu_encoder_phys_wb *wb_enc = NULL;
+	int ret = 0;
+	int i;
+
+	DPU_DEBUG("\n");
+
+	if (!p || !p->parent) {
+		DPU_ERROR("invalid params\n");
+		ret = -EINVAL;
+		goto fail_alloc;
+	}
+
+	wb_enc = kzalloc(sizeof(*wb_enc), GFP_KERNEL);
+	if (!wb_enc) {
+		DPU_ERROR("failed to allocate wb phys_enc enc\n");
+		ret = -ENOMEM;
+		goto fail_alloc;
+	}
+
+	phys_enc = &wb_enc->base;
+	phys_enc->hw_mdptop = p->dpu_kms->hw_mdp;
+	phys_enc->wb_idx = p->wb_idx;
+
+	dpu_encoder_phys_wb_init_ops(&phys_enc->ops);
+	phys_enc->parent = p->parent;
+	phys_enc->parent_ops = p->parent_ops;
+	phys_enc->dpu_kms = p->dpu_kms;
+	phys_enc->split_role = p->split_role;
+	phys_enc->intf_mode = INTF_MODE_WB_LINE;
+	phys_enc->wb_idx = p->wb_idx;
+	phys_enc->enc_spinlock = p->enc_spinlock;
+
+	atomic_set(&wb_enc->wbirq_refcount, 0);
+
+	for (i = 0; i < ARRAY_SIZE(phys_enc->irq); i++)
+		phys_enc->irq[i] = -EINVAL;
+
+	atomic_set(&phys_enc->pending_kickoff_cnt, 0);
+	atomic_set(&phys_enc->vblank_refcount, 0);
+	wb_enc->wb_done_timeout_cnt = 0;
+
+	init_waitqueue_head(&phys_enc->pending_kickoff_wq);
+	phys_enc->enable_state = DPU_ENC_DISABLED;
+
+	DPU_DEBUG("Created dpu_encoder_phys for wb %d\n",
+			phys_enc->wb_idx);
+
+	return phys_enc;
+
+fail_alloc:
+	return ERR_PTR(ret);
+}
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v5 14/19] drm/msm/dpu: add the writeback connector layer
  2022-04-25  0:31 [PATCH v5 00/19] Add writeback block support for DPU Abhinav Kumar
                   ` (12 preceding siblings ...)
  2022-04-25  0:32 ` [PATCH v5 13/19] drm/msm/dpu: introduce the dpu_encoder_phys_* for writeback Abhinav Kumar
@ 2022-04-25  0:32 ` Abhinav Kumar
  2022-04-26  0:20   ` Dmitry Baryshkov
  2022-04-25  0:32 ` [PATCH v5 15/19] drm/msm/dpu: initialize dpu encoder and connector for writeback Abhinav Kumar
                   ` (4 subsequent siblings)
  18 siblings, 1 reply; 29+ messages in thread
From: Abhinav Kumar @ 2022-04-25  0:32 UTC (permalink / raw)
  To: freedreno
  Cc: markyacoub, liviu.dudau, Abhinav Kumar, dri-devel, swboyd,
	seanpaul, laurent.pinchart, dmitry.baryshkov, quic_jesszhan,
	quic_aravindh

Introduce the dpu_writeback module which serves as the
interface between dpu operations and the drm_writeback.

This module manages the connector related operations for
dpu writeback.

changes in v2:
	- start using drm_writeback_connector_init_with_encoder()
	- drop unnecessary arguments from dpu_writeback_init()
	- rebase on msm-next tip and remove usage of priv->connectors

changes in v3:
	- none

changes in v4:
	- none

changes in v5:
	- store the drm_enc in the dpu_wb_conn to be used while
	  using dpu_encoder APIs

Signed-off-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
---
 drivers/gpu/drm/msm/Makefile                  |  1 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c | 76 +++++++++++++++++++++++++++
 drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.h | 31 +++++++++++
 3 files changed, 108 insertions(+)
 create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c
 create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.h

diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index 0387f22..66395ee 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -80,6 +80,7 @@ msm-$(CONFIG_DRM_MSM_DPU) += \
 	disp/dpu1/dpu_plane.o \
 	disp/dpu1/dpu_rm.o \
 	disp/dpu1/dpu_vbif.o \
+	disp/dpu1/dpu_writeback.o
 
 msm-$(CONFIG_DRM_MSM_MDSS) += \
 	msm_mdss.o \
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c
new file mode 100644
index 0000000..7620ffe
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c
@@ -0,0 +1,76 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include "dpu_writeback.h"
+
+static int dpu_wb_conn_get_modes(struct drm_connector *connector)
+{
+	struct drm_device *dev = connector->dev;
+
+	return drm_add_modes_noedid(connector, dev->mode_config.max_width,
+			dev->mode_config.max_height);
+}
+
+static const struct drm_connector_funcs dpu_wb_conn_funcs = {
+	.reset = drm_atomic_helper_connector_reset,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.destroy = drm_connector_cleanup,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static int dpu_wb_conn_prepare_job(struct drm_writeback_connector *connector,
+		struct drm_writeback_job *job)
+{
+
+	struct dpu_wb_connector *dpu_wb_conn = to_dpu_wb_conn(connector);
+
+	if (!job->fb)
+		return 0;
+
+	dpu_encoder_prepare_wb_job(dpu_wb_conn->wb_enc, job);
+
+	return 0;
+}
+
+static void dpu_wb_conn_cleanup_job(struct drm_writeback_connector *connector,
+		struct drm_writeback_job *job)
+{
+	struct dpu_wb_connector *dpu_wb_conn = to_dpu_wb_conn(connector);
+
+	if (!job->fb)
+		return;
+
+	dpu_encoder_cleanup_wb_job(dpu_wb_conn->wb_enc, job);
+}
+
+static const struct drm_connector_helper_funcs dpu_wb_conn_helper_funcs = {
+	.get_modes = dpu_wb_conn_get_modes,
+	.prepare_writeback_job = dpu_wb_conn_prepare_job,
+	.cleanup_writeback_job = dpu_wb_conn_cleanup_job,
+};
+
+int dpu_writeback_init(struct drm_device *dev, struct drm_encoder *enc,
+		const u32 *format_list, u32 num_formats)
+{
+	struct dpu_wb_connector *dpu_wb_conn;
+	int rc = 0;
+
+	dpu_wb_conn = devm_kzalloc(dev->dev, sizeof(*dpu_wb_conn), GFP_KERNEL);
+
+	drm_connector_helper_add(&dpu_wb_conn->base.base, &dpu_wb_conn_helper_funcs);
+
+	/* DPU initializes the encoder and sets it up completely for writeback
+	 * cases and hence should use the new API drm_writeback_connector_init_with_encoder
+	 * to initialize the writeback connector
+	 */
+	rc = drm_writeback_connector_init_with_encoder(dev, &dpu_wb_conn->base, enc,
+			&dpu_wb_conn_funcs, format_list, num_formats);
+
+	if (!rc)
+		dpu_wb_conn->wb_enc = enc;
+
+	return rc;
+}
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.h
new file mode 100644
index 0000000..5a75ea9
--- /dev/null
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _DPU_WRITEBACK_H
+#define _DPU_WRITEBACK_H
+
+#include <drm/drm_crtc.h>
+#include <drm/drm_file.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_writeback.h>
+
+#include "msm_drv.h"
+#include "dpu_kms.h"
+#include "dpu_encoder_phys.h"
+
+struct dpu_wb_connector {
+	struct drm_writeback_connector base;
+	struct drm_encoder *wb_enc;
+};
+
+static inline struct dpu_wb_connector *to_dpu_wb_conn(struct drm_writeback_connector *conn)
+{
+	return container_of(conn, struct dpu_wb_connector, base);
+}
+
+int dpu_writeback_init(struct drm_device *dev, struct drm_encoder *enc,
+		const u32 *format_list, u32 num_formats);
+
+#endif /*_DPU_WRITEBACK_H */
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v5 15/19] drm/msm/dpu: initialize dpu encoder and connector for writeback
  2022-04-25  0:31 [PATCH v5 00/19] Add writeback block support for DPU Abhinav Kumar
                   ` (13 preceding siblings ...)
  2022-04-25  0:32 ` [PATCH v5 14/19] drm/msm/dpu: add the writeback connector layer Abhinav Kumar
@ 2022-04-25  0:32 ` Abhinav Kumar
  2022-04-26  0:32   ` Laurent Pinchart
  2022-04-25  0:32 ` [PATCH v5 16/19] drm/msm/dpu: gracefully handle null fb commits " Abhinav Kumar
                   ` (3 subsequent siblings)
  18 siblings, 1 reply; 29+ messages in thread
From: Abhinav Kumar @ 2022-04-25  0:32 UTC (permalink / raw)
  To: freedreno
  Cc: markyacoub, liviu.dudau, Abhinav Kumar, dri-devel, swboyd,
	seanpaul, laurent.pinchart, dmitry.baryshkov, quic_jesszhan,
	quic_aravindh

Initialize dpu encoder and connector for writeback if the
target supports it in the catalog.

changes in v2:
	- start initialing the encoder for writeback since we
	have migrated to using drm_writeback_connector_init_with_encoder()
	- instead of checking for WB_2 inside _dpu_kms_initialize_writeback
	call it only when its WB_2
	- rebase on tip of msm-next and remove usage of priv->encoders

changes in v3:
	- none

changes in v4:
	- fix copyright years order

Signed-off-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 27 +++++++++----
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c     | 61 ++++++++++++++++++++++++++++-
 2 files changed, 80 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 24870eb..2d79002 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -2102,7 +2102,7 @@ static void dpu_encoder_early_unregister(struct drm_encoder *encoder)
 }
 
 static int dpu_encoder_virt_add_phys_encs(
-		u32 display_caps,
+		struct msm_display_info *disp_info,
 		struct dpu_encoder_virt *dpu_enc,
 		struct dpu_enc_phys_init_params *params)
 {
@@ -2121,7 +2121,7 @@ static int dpu_encoder_virt_add_phys_encs(
 		return -EINVAL;
 	}
 
-	if (display_caps & MSM_DISPLAY_CAP_VID_MODE) {
+	if (disp_info->capabilities & MSM_DISPLAY_CAP_VID_MODE) {
 		enc = dpu_encoder_phys_vid_init(params);
 
 		if (IS_ERR_OR_NULL(enc)) {
@@ -2134,7 +2134,7 @@ static int dpu_encoder_virt_add_phys_encs(
 		++dpu_enc->num_phys_encs;
 	}
 
-	if (display_caps & MSM_DISPLAY_CAP_CMD_MODE) {
+	if (disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) {
 		enc = dpu_encoder_phys_cmd_init(params);
 
 		if (IS_ERR_OR_NULL(enc)) {
@@ -2147,6 +2147,19 @@ static int dpu_encoder_virt_add_phys_encs(
 		++dpu_enc->num_phys_encs;
 	}
 
+	if (disp_info->intf_type == DRM_MODE_ENCODER_VIRTUAL) {
+		enc = dpu_encoder_phys_wb_init(params);
+
+		if (IS_ERR_OR_NULL(enc)) {
+			DPU_ERROR_ENC(dpu_enc, "failed to init wb enc: %ld\n",
+					PTR_ERR(enc));
+			return enc == NULL ? -EINVAL : PTR_ERR(enc);
+		}
+
+		dpu_enc->phys_encs[dpu_enc->num_phys_encs] = enc;
+		++dpu_enc->num_phys_encs;
+	}
+
 	if (params->split_role == ENC_ROLE_SLAVE)
 		dpu_enc->cur_slave = enc;
 	else
@@ -2248,9 +2261,8 @@ static int dpu_encoder_setup_display(struct dpu_encoder_virt *dpu_enc,
 		}
 
 		if (!ret) {
-			ret = dpu_encoder_virt_add_phys_encs(disp_info->capabilities,
-												 dpu_enc,
-												 &phys_params);
+			ret = dpu_encoder_virt_add_phys_encs(disp_info,
+					dpu_enc, &phys_params);
 			if (ret)
 				DPU_ERROR_ENC(dpu_enc, "failed to add phys encs\n");
 		}
@@ -2367,8 +2379,9 @@ struct drm_encoder *dpu_encoder_init(struct drm_device *dev,
 	if (!dpu_enc)
 		return ERR_PTR(-ENOMEM);
 
+
 	rc = drm_encoder_init(dev, &dpu_enc->base, &dpu_encoder_funcs,
-			drm_enc_mode, NULL);
+							  drm_enc_mode, NULL);
 	if (rc) {
 		devm_kfree(dev->dev, dpu_enc);
 		return ERR_PTR(rc);
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
index c683cab..9a406e1 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
@@ -1,7 +1,9 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
  * Copyright (C) 2013 Red Hat
+ * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ *
  * Author: Rob Clark <robdclark@gmail.com>
  */
 
@@ -15,6 +17,7 @@
 #include <drm/drm_crtc.h>
 #include <drm/drm_file.h>
 #include <drm/drm_vblank.h>
+#include <drm/drm_writeback.h>
 
 #include "msm_drv.h"
 #include "msm_mmu.h"
@@ -29,6 +32,7 @@
 #include "dpu_kms.h"
 #include "dpu_plane.h"
 #include "dpu_vbif.h"
+#include "dpu_writeback.h"
 
 #define CREATE_TRACE_POINTS
 #include "dpu_trace.h"
@@ -648,6 +652,45 @@ static int _dpu_kms_initialize_displayport(struct drm_device *dev,
 	return 0;
 }
 
+static int _dpu_kms_initialize_writeback(struct drm_device *dev,
+		struct msm_drm_private *priv, struct dpu_kms *dpu_kms,
+		const u32 *wb_formats, int n_formats)
+{
+	struct drm_encoder *encoder = NULL;
+	struct msm_display_info info;
+	int rc;
+
+	encoder = dpu_encoder_init(dev, DRM_MODE_ENCODER_VIRTUAL);
+	if (IS_ERR(encoder)) {
+		DPU_ERROR("encoder init failed for dsi display\n");
+		return PTR_ERR(encoder);
+	}
+
+	memset(&info, 0, sizeof(info));
+
+	rc = dpu_writeback_init(dev, encoder, wb_formats,
+			n_formats);
+	if (rc) {
+		DPU_ERROR("dpu_writeback_init, rc = %d\n", rc);
+		drm_encoder_cleanup(encoder);
+		return rc;
+	}
+
+	info.num_of_h_tiles = 1;
+	/* use only WB idx 2 instance for DPU */
+	info.h_tile_instance[0] = WB_2;
+	info.intf_type = encoder->encoder_type;
+
+	rc = dpu_encoder_setup(dev, encoder, &info);
+	if (rc) {
+		DPU_ERROR("failed to setup DPU encoder %d: rc:%d\n",
+				  encoder->base.id, rc);
+		return rc;
+	}
+
+	return 0;
+}
+
 /**
  * _dpu_kms_setup_displays - create encoders, bridges and connectors
  *                           for underlying displays
@@ -661,6 +704,7 @@ static int _dpu_kms_setup_displays(struct drm_device *dev,
 				    struct dpu_kms *dpu_kms)
 {
 	int rc = 0;
+	int i;
 
 	rc = _dpu_kms_initialize_dsi(dev, priv, dpu_kms);
 	if (rc) {
@@ -674,6 +718,21 @@ static int _dpu_kms_setup_displays(struct drm_device *dev,
 		return rc;
 	}
 
+	/* Since WB isn't a driver check the catalog before initializing */
+	if (dpu_kms->catalog->wb_count) {
+		for (i = 0; i < dpu_kms->catalog->wb_count; i++) {
+			if (dpu_kms->catalog->wb[i].id == WB_2) {
+				rc = _dpu_kms_initialize_writeback(dev, priv, dpu_kms,
+						dpu_kms->catalog->wb[i].format_list,
+						dpu_kms->catalog->wb[i].num_formats);
+				if (rc) {
+					DPU_ERROR("initialize_WB failed, rc = %d\n", rc);
+					return rc;
+				}
+			}
+		}
+	}
+
 	return rc;
 }
 
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v5 16/19] drm/msm/dpu: gracefully handle null fb commits for writeback
  2022-04-25  0:31 [PATCH v5 00/19] Add writeback block support for DPU Abhinav Kumar
                   ` (14 preceding siblings ...)
  2022-04-25  0:32 ` [PATCH v5 15/19] drm/msm/dpu: initialize dpu encoder and connector for writeback Abhinav Kumar
@ 2022-04-25  0:32 ` Abhinav Kumar
  2022-04-25  0:32 ` [PATCH v5 17/19] drm/msm/dpu: add writeback blocks to the display snapshot Abhinav Kumar
                   ` (2 subsequent siblings)
  18 siblings, 0 replies; 29+ messages in thread
From: Abhinav Kumar @ 2022-04-25  0:32 UTC (permalink / raw)
  To: freedreno
  Cc: markyacoub, liviu.dudau, Abhinav Kumar, dri-devel, swboyd,
	seanpaul, laurent.pinchart, dmitry.baryshkov, quic_jesszhan,
	quic_aravindh

kms_writeback test cases also verify with a null fb for the
writeback connector job. In addition there are also other
commit paths which can result in kickoffs without a valid
framebuffer like while closing the fb which results in the
callback to drm_atomic_helper_dirtyfb() which internally
triggers a commit.

Add protection in the dpu driver to ensure that commits for
writeback encoders without a valid fb are gracefully skipped.

changes in v2:
	- rename dpu_encoder_has_valid_fb to dpu_encoder_is_valid_for_commit

changes in v3:
	- none

Signed-off-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c            |  9 +++++++++
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c         | 21 +++++++++++++++++++++
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h         |  6 ++++++
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h    |  1 +
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c | 12 ++++++++++++
 5 files changed, 49 insertions(+)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
index 7763558..d65e124 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
@@ -869,6 +869,13 @@ void dpu_crtc_commit_kickoff(struct drm_crtc *crtc)
 
 	DPU_ATRACE_BEGIN("crtc_commit");
 
+	drm_for_each_encoder_mask(encoder, crtc->dev,
+			crtc->state->encoder_mask) {
+		if (!dpu_encoder_is_valid_for_commit(encoder)) {
+			DRM_DEBUG_ATOMIC("invalid FB not kicking off crtc\n");
+			goto end;
+		}
+	}
 	/*
 	 * Encoder will flush/start now, unless it has a tx pending. If so, it
 	 * may delay and flush at an irq event (e.g. ppdone)
@@ -891,6 +898,8 @@ void dpu_crtc_commit_kickoff(struct drm_crtc *crtc)
 		dpu_encoder_kickoff(encoder);
 
 	reinit_completion(&dpu_crtc->frame_done_comp);
+
+end:
 	DPU_ATRACE_END("crtc_commit");
 }
 
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 2d79002..90ef807 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -1862,6 +1862,27 @@ void dpu_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc)
 		dpu_encoder_prep_dsc(dpu_enc, dpu_enc->dsc);
 }
 
+bool dpu_encoder_is_valid_for_commit(struct drm_encoder *drm_enc)
+{
+	struct dpu_encoder_virt *dpu_enc;
+	unsigned int i;
+	struct dpu_encoder_phys *phys;
+
+	dpu_enc = to_dpu_encoder_virt(drm_enc);
+
+	if (drm_enc->encoder_type == DRM_MODE_ENCODER_VIRTUAL) {
+		for (i = 0; i < dpu_enc->num_phys_encs; i++) {
+			phys = dpu_enc->phys_encs[i];
+			if (phys->ops.is_valid_for_commit && !phys->ops.is_valid_for_commit(phys)) {
+				DPU_DEBUG("invalid FB not kicking off\n");
+				return false;
+			}
+		}
+	}
+
+	return true;
+}
+
 void dpu_encoder_kickoff(struct drm_encoder *drm_enc)
 {
 	struct dpu_encoder_virt *dpu_enc;
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
index 6ceec1d..781d41c 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.h
@@ -196,4 +196,10 @@ void dpu_encoder_prepare_wb_job(struct drm_encoder *drm_enc,
 void dpu_encoder_cleanup_wb_job(struct drm_encoder *drm_enc,
 		struct drm_writeback_job *job);
 
+/**
+ * dpu_encoder_is_valid_for_commit - check if encode has valid parameters for commit.
+ * @drm_enc:    Pointer to drm encoder structure
+ */
+bool dpu_encoder_is_valid_for_commit(struct drm_encoder *drm_enc);
+
 #endif /* __DPU_ENCODER_H__ */
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
index bed4523..f2af07d 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
@@ -142,6 +142,7 @@ struct dpu_encoder_phys_ops {
 			struct drm_writeback_job *job);
 	void (*cleanup_wb_job)(struct dpu_encoder_phys *phys_enc,
 			struct drm_writeback_job *job);
+	bool (*is_valid_for_commit)(struct dpu_encoder_phys *phys_enc);
 };
 
 /**
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
index 4ab2699..cb5c7da 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c
@@ -667,6 +667,16 @@ static void dpu_encoder_phys_wb_cleanup_wb_job(struct dpu_encoder_phys *phys_enc
 	wb_enc->wb_conn = NULL;
 }
 
+static bool dpu_encoder_phys_wb_is_valid_for_commit(struct dpu_encoder_phys *phys_enc)
+{
+	struct dpu_encoder_phys_wb *wb_enc = to_dpu_encoder_phys_wb(phys_enc);
+
+	if (wb_enc->wb_job)
+		return true;
+	else
+		return false;
+}
+
 /**
  * dpu_encoder_phys_wb_init_ops - initialize writeback operations
  * @ops:	Pointer to encoder operation table
@@ -687,6 +697,8 @@ static void dpu_encoder_phys_wb_init_ops(struct dpu_encoder_phys_ops *ops)
 	ops->prepare_wb_job = dpu_encoder_phys_wb_prepare_wb_job;
 	ops->cleanup_wb_job = dpu_encoder_phys_wb_cleanup_wb_job;
 	ops->irq_control = dpu_encoder_phys_wb_irq_ctrl;
+	ops->is_valid_for_commit = dpu_encoder_phys_wb_is_valid_for_commit;
+
 }
 
 /**
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v5 17/19] drm/msm/dpu: add writeback blocks to the display snapshot
  2022-04-25  0:31 [PATCH v5 00/19] Add writeback block support for DPU Abhinav Kumar
                   ` (15 preceding siblings ...)
  2022-04-25  0:32 ` [PATCH v5 16/19] drm/msm/dpu: gracefully handle null fb commits " Abhinav Kumar
@ 2022-04-25  0:32 ` Abhinav Kumar
  2022-04-25  0:32 ` [PATCH v5 18/19] drm/msm/dpu: add wb_idx to existing DRM prints in dpu_encoder Abhinav Kumar
  2022-04-25  0:32 ` [PATCH v5 19/19] drm/msm/dpu: add wb_idx to DRM traces " Abhinav Kumar
  18 siblings, 0 replies; 29+ messages in thread
From: Abhinav Kumar @ 2022-04-25  0:32 UTC (permalink / raw)
  To: freedreno
  Cc: markyacoub, liviu.dudau, Abhinav Kumar, dri-devel, swboyd,
	seanpaul, laurent.pinchart, dmitry.baryshkov, quic_jesszhan,
	quic_aravindh

Add writeback block information while capturing the display
snapshot.

Signed-off-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
index 9a406e1..b18bff8 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
@@ -945,6 +945,11 @@ static void dpu_kms_mdp_snapshot(struct msm_disp_state *disp_state, struct msm_k
 		msm_disp_snapshot_add_block(disp_state, cat->mixer[i].len,
 				dpu_kms->mmio + cat->mixer[i].base, "lm_%d", i);
 
+	/* dump WB sub-blocks HW regs info */
+	for (i = 0; i < cat->wb_count; i++)
+		msm_disp_snapshot_add_block(disp_state, cat->wb[i].len,
+				dpu_kms->mmio + cat->wb[i].base, "wb_%d", i);
+
 	msm_disp_snapshot_add_block(disp_state, top->hw.length,
 			dpu_kms->mmio + top->hw.blk_off, "top");
 
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v5 18/19] drm/msm/dpu: add wb_idx to existing DRM prints in dpu_encoder
  2022-04-25  0:31 [PATCH v5 00/19] Add writeback block support for DPU Abhinav Kumar
                   ` (16 preceding siblings ...)
  2022-04-25  0:32 ` [PATCH v5 17/19] drm/msm/dpu: add writeback blocks to the display snapshot Abhinav Kumar
@ 2022-04-25  0:32 ` Abhinav Kumar
  2022-04-25  0:32 ` [PATCH v5 19/19] drm/msm/dpu: add wb_idx to DRM traces " Abhinav Kumar
  18 siblings, 0 replies; 29+ messages in thread
From: Abhinav Kumar @ 2022-04-25  0:32 UTC (permalink / raw)
  To: freedreno
  Cc: markyacoub, liviu.dudau, Abhinav Kumar, dri-devel, swboyd,
	seanpaul, laurent.pinchart, dmitry.baryshkov, quic_jesszhan,
	quic_aravindh

Add wb_idx to existing DRM prints in dpu_encoder and also
print the intf_mode so that its clear that for any INTF_CMD/VID
there will be a valid intf_idx and any INTF_WB_* there will be a
valid wb_idx.

Update the debugfs to add the same information. Here is a sample
output with this change:

root:/sys/kernel/debug/dri/0/encoder31# cat status
intf:1  wb:-1  vsync: 31  underrun: 0    mode: INTF_MODE_VIDEO
root:/sys/kernel/debug/dri/0/encoder33# cat status
intf:-1  wb:2  vsync:  7  underrun: 0    mode: INTF_MODE_WB_LINE

Also remove DPU_DEBUG_PHYS macros as its unused because the
respective dpu_encoder_phys_* files have their own macros.

changes in v2:
	- use switch case instead of if/else-if for get_intf_type

Signed-off-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 52 +++++++++++++----------------
 1 file changed, 24 insertions(+), 28 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 90ef807..6d093cf 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -38,18 +38,6 @@
 #define DPU_ERROR_ENC(e, fmt, ...) DPU_ERROR("enc%d " fmt,\
 		(e) ? (e)->base.base.id : -1, ##__VA_ARGS__)
 
-#define DPU_DEBUG_PHYS(p, fmt, ...) DRM_DEBUG_ATOMIC("enc%d intf%d pp%d " fmt,\
-		(p) ? (p)->parent->base.id : -1, \
-		(p) ? (p)->intf_idx - INTF_0 : -1, \
-		(p) ? ((p)->hw_pp ? (p)->hw_pp->idx - PINGPONG_0 : -1) : -1, \
-		##__VA_ARGS__)
-
-#define DPU_ERROR_PHYS(p, fmt, ...) DPU_ERROR("enc%d intf%d pp%d " fmt,\
-		(p) ? (p)->parent->base.id : -1, \
-		(p) ? (p)->intf_idx - INTF_0 : -1, \
-		(p) ? ((p)->hw_pp ? (p)->hw_pp->idx - PINGPONG_0 : -1) : -1, \
-		##__VA_ARGS__)
-
 /*
  * Two to anticipate panels that can do cmd/vid dynamic switching
  * plan is to create all possible physical encoder types, and switch between
@@ -263,12 +251,30 @@ static void _dpu_encoder_setup_dither(struct dpu_hw_pingpong *hw_pp, unsigned bp
 	hw_pp->ops.setup_dither(hw_pp, &dither_cfg);
 }
 
+static char *dpu_encoder_helper_get_intf_type(enum dpu_intf_mode intf_mode)
+{
+	switch (intf_mode) {
+	case INTF_MODE_VIDEO:
+		return "INTF_MODE_VIDEO";
+	case INTF_MODE_CMD:
+		return "INTF_MODE_CMD";
+	case INTF_MODE_WB_BLOCK:
+		return "INTF_MODE_WB_BLOCK";
+	case INTF_MODE_WB_LINE:
+		return "INTF_MODE_WB_LINE";
+	default:
+		return "INTF_MODE_UNKNOWN";
+	}
+}
+
 void dpu_encoder_helper_report_irq_timeout(struct dpu_encoder_phys *phys_enc,
 		enum dpu_intr_idx intr_idx)
 {
-	DRM_ERROR("irq timeout id=%u, intf=%d, pp=%d, intr=%d\n",
-		  DRMID(phys_enc->parent), phys_enc->intf_idx - INTF_0,
-		  phys_enc->hw_pp->idx - PINGPONG_0, intr_idx);
+	DRM_ERROR("irq timeout id=%u, intf_mode=%s intf=%d wb=%d, pp=%d, intr=%d\n",
+			DRMID(phys_enc->parent),
+			dpu_encoder_helper_get_intf_type(phys_enc->intf_mode),
+			phys_enc->intf_idx - INTF_0, phys_enc->wb_idx - WB_0,
+			phys_enc->hw_pp->idx - PINGPONG_0, intr_idx);
 
 	if (phys_enc->parent_ops->handle_frame_done)
 		phys_enc->parent_ops->handle_frame_done(
@@ -2049,22 +2055,12 @@ static int _dpu_encoder_status_show(struct seq_file *s, void *data)
 	for (i = 0; i < dpu_enc->num_phys_encs; i++) {
 		struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i];
 
-		seq_printf(s, "intf:%d    vsync:%8d     underrun:%8d    ",
-				phys->intf_idx - INTF_0,
+		seq_printf(s, "intf:%d  wb:%d  vsync:%8d     underrun:%8d    ",
+				phys->intf_idx - INTF_0, phys->wb_idx - WB_0,
 				atomic_read(&phys->vsync_cnt),
 				atomic_read(&phys->underrun_cnt));
 
-		switch (phys->intf_mode) {
-		case INTF_MODE_VIDEO:
-			seq_puts(s, "mode: video\n");
-			break;
-		case INTF_MODE_CMD:
-			seq_puts(s, "mode: command\n");
-			break;
-		default:
-			seq_puts(s, "mode: ???\n");
-			break;
-		}
+		seq_printf(s, "mode: %s\n", dpu_encoder_helper_get_intf_type(phys->intf_mode));
 	}
 	mutex_unlock(&dpu_enc->enc_lock);
 
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v5 19/19] drm/msm/dpu: add wb_idx to DRM traces in dpu_encoder
  2022-04-25  0:31 [PATCH v5 00/19] Add writeback block support for DPU Abhinav Kumar
                   ` (17 preceding siblings ...)
  2022-04-25  0:32 ` [PATCH v5 18/19] drm/msm/dpu: add wb_idx to existing DRM prints in dpu_encoder Abhinav Kumar
@ 2022-04-25  0:32 ` Abhinav Kumar
  18 siblings, 0 replies; 29+ messages in thread
From: Abhinav Kumar @ 2022-04-25  0:32 UTC (permalink / raw)
  To: freedreno
  Cc: markyacoub, liviu.dudau, Abhinav Kumar, dri-devel, swboyd,
	seanpaul, laurent.pinchart, dmitry.baryshkov, quic_jesszhan,
	quic_aravindh

Change the DRM traces to include both the intf_mode
and wb_idx similar to the DRM prints in the previous change.

Signed-off-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
 drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 13 ++++++++-----
 drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h   | 26 ++++++++++++++++++--------
 2 files changed, 26 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
index 6d093cf..3bd1790 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
@@ -1354,8 +1354,9 @@ static void dpu_encoder_frame_done_callback(
 			 * suppress frame_done without waiter,
 			 * likely autorefresh
 			 */
-			trace_dpu_enc_frame_done_cb_not_busy(DRMID(drm_enc),
-					event, ready_phys->intf_idx);
+			trace_dpu_enc_frame_done_cb_not_busy(DRMID(drm_enc), event,
+					dpu_encoder_helper_get_intf_type(ready_phys->intf_mode),
+					ready_phys->intf_idx, ready_phys->wb_idx);
 			return;
 		}
 
@@ -1433,9 +1434,11 @@ static void _dpu_encoder_trigger_flush(struct drm_encoder *drm_enc,
 	if (ctl->ops.get_pending_flush)
 		ret = ctl->ops.get_pending_flush(ctl);
 
-	trace_dpu_enc_trigger_flush(DRMID(drm_enc), phys->intf_idx,
-				    pending_kickoff_cnt, ctl->idx,
-				    extra_flush_bits, ret);
+	trace_dpu_enc_trigger_flush(DRMID(drm_enc),
+			dpu_encoder_helper_get_intf_type(phys->intf_mode),
+			phys->intf_idx, phys->wb_idx,
+			pending_kickoff_cnt, ctl->idx,
+			extra_flush_bits, ret);
 }
 
 /**
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h
index 58b411f..1106d44 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_trace.h
@@ -380,20 +380,26 @@ TRACE_EVENT(dpu_enc_rc,
 );
 
 TRACE_EVENT(dpu_enc_frame_done_cb_not_busy,
-	TP_PROTO(uint32_t drm_id, u32 event, enum dpu_intf intf_idx),
-	TP_ARGS(drm_id, event, intf_idx),
+	TP_PROTO(uint32_t drm_id, u32 event, char *intf_mode, enum dpu_intf intf_idx,
+			enum dpu_wb wb_idx),
+	TP_ARGS(drm_id, event, intf_mode, intf_idx, wb_idx),
 	TP_STRUCT__entry(
 		__field(	uint32_t,	drm_id		)
 		__field(	u32,		event		)
+		__string(	intf_mode_str,		intf_mode	)
 		__field(	enum dpu_intf,	intf_idx	)
+		__field(    enum dpu_wb,  wb_idx    )
 	),
 	TP_fast_assign(
 		__entry->drm_id = drm_id;
 		__entry->event = event;
+		__assign_str(intf_mode_str, intf_mode);
 		__entry->intf_idx = intf_idx;
+		__entry->wb_idx = wb_idx;
 	),
-	TP_printk("id=%u, event=%u, intf=%d", __entry->drm_id, __entry->event,
-		  __entry->intf_idx)
+	TP_printk("id=%u, event=%u, intf_mode=%s intf=%d wb=%d", __entry->drm_id,
+			__entry->event, __get_str(intf_mode_str),
+			__entry->intf_idx, __entry->wb_idx)
 );
 
 TRACE_EVENT(dpu_enc_frame_done_cb,
@@ -415,14 +421,16 @@ TRACE_EVENT(dpu_enc_frame_done_cb,
 );
 
 TRACE_EVENT(dpu_enc_trigger_flush,
-	TP_PROTO(uint32_t drm_id, enum dpu_intf intf_idx,
+	TP_PROTO(uint32_t drm_id, char *intf_mode, enum dpu_intf intf_idx, enum dpu_wb wb_idx,
 		 int pending_kickoff_cnt, int ctl_idx, u32 extra_flush_bits,
 		 u32 pending_flush_ret),
-	TP_ARGS(drm_id, intf_idx, pending_kickoff_cnt, ctl_idx,
+	TP_ARGS(drm_id, intf_mode, intf_idx, pending_kickoff_cnt, ctl_idx,
 		extra_flush_bits, pending_flush_ret),
 	TP_STRUCT__entry(
 		__field(	uint32_t,	drm_id			)
+		__string(	intf_mode_str,	intf_mode	)
 		__field(	enum dpu_intf,	intf_idx		)
+		__field(    enum dpu_wb,  wb_idx        )
 		__field(	int,		pending_kickoff_cnt	)
 		__field(	int,		ctl_idx			)
 		__field(	u32,		extra_flush_bits	)
@@ -430,15 +438,17 @@ TRACE_EVENT(dpu_enc_trigger_flush,
 	),
 	TP_fast_assign(
 		__entry->drm_id = drm_id;
+		__assign_str(intf_mode_str, intf_mode);
 		__entry->intf_idx = intf_idx;
+		__entry->wb_idx = wb_idx;
 		__entry->pending_kickoff_cnt = pending_kickoff_cnt;
 		__entry->ctl_idx = ctl_idx;
 		__entry->extra_flush_bits = extra_flush_bits;
 		__entry->pending_flush_ret = pending_flush_ret;
 	),
-	TP_printk("id=%u, intf_idx=%d, pending_kickoff_cnt=%d ctl_idx=%d "
+	TP_printk("id=%u, intf_mode=%s, intf_idx=%d, wb_idx=%d, pending_kickoff_cnt=%d ctl_idx=%d "
 		  "extra_flush_bits=0x%x pending_flush_ret=0x%x",
-		  __entry->drm_id, __entry->intf_idx,
+		  __entry->drm_id, __get_str(intf_mode_str), __entry->intf_idx, __entry->wb_idx,
 		  __entry->pending_kickoff_cnt, __entry->ctl_idx,
 		  __entry->extra_flush_bits, __entry->pending_flush_ret)
 );
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* Re: [PATCH v5 14/19] drm/msm/dpu: add the writeback connector layer
  2022-04-25  0:32 ` [PATCH v5 14/19] drm/msm/dpu: add the writeback connector layer Abhinav Kumar
@ 2022-04-26  0:20   ` Dmitry Baryshkov
  0 siblings, 0 replies; 29+ messages in thread
From: Dmitry Baryshkov @ 2022-04-26  0:20 UTC (permalink / raw)
  To: Abhinav Kumar, freedreno
  Cc: markyacoub, liviu.dudau, dri-devel, swboyd, seanpaul,
	laurent.pinchart, quic_jesszhan, quic_aravindh

On 25/04/2022 03:32, Abhinav Kumar wrote:
> Introduce the dpu_writeback module which serves as the
> interface between dpu operations and the drm_writeback.
> 
> This module manages the connector related operations for
> dpu writeback.
> 
> changes in v2:
> 	- start using drm_writeback_connector_init_with_encoder()
> 	- drop unnecessary arguments from dpu_writeback_init()
> 	- rebase on msm-next tip and remove usage of priv->connectors
> 
> changes in v3:
> 	- none
> 
> changes in v4:
> 	- none
> 
> changes in v5:
> 	- store the drm_enc in the dpu_wb_conn to be used while
> 	  using dpu_encoder APIs
> 
> Signed-off-by: Abhinav Kumar <quic_abhinavk@quicinc.com>

Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>

> ---
>   drivers/gpu/drm/msm/Makefile                  |  1 +
>   drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c | 76 +++++++++++++++++++++++++++
>   drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.h | 31 +++++++++++
>   3 files changed, 108 insertions(+)
>   create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c
>   create mode 100644 drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.h
> 
> diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
> index 0387f22..66395ee 100644
> --- a/drivers/gpu/drm/msm/Makefile
> +++ b/drivers/gpu/drm/msm/Makefile
> @@ -80,6 +80,7 @@ msm-$(CONFIG_DRM_MSM_DPU) += \
>   	disp/dpu1/dpu_plane.o \
>   	disp/dpu1/dpu_rm.o \
>   	disp/dpu1/dpu_vbif.o \
> +	disp/dpu1/dpu_writeback.o
>   
>   msm-$(CONFIG_DRM_MSM_MDSS) += \
>   	msm_mdss.o \
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c
> new file mode 100644
> index 0000000..7620ffe
> --- /dev/null
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.c
> @@ -0,0 +1,76 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
> + */
> +
> +#include "dpu_writeback.h"
> +
> +static int dpu_wb_conn_get_modes(struct drm_connector *connector)
> +{
> +	struct drm_device *dev = connector->dev;
> +
> +	return drm_add_modes_noedid(connector, dev->mode_config.max_width,
> +			dev->mode_config.max_height);
> +}
> +
> +static const struct drm_connector_funcs dpu_wb_conn_funcs = {
> +	.reset = drm_atomic_helper_connector_reset,
> +	.fill_modes = drm_helper_probe_single_connector_modes,
> +	.destroy = drm_connector_cleanup,
> +	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> +	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> +};
> +
> +static int dpu_wb_conn_prepare_job(struct drm_writeback_connector *connector,
> +		struct drm_writeback_job *job)
> +{
> +
> +	struct dpu_wb_connector *dpu_wb_conn = to_dpu_wb_conn(connector);
> +
> +	if (!job->fb)
> +		return 0;
> +
> +	dpu_encoder_prepare_wb_job(dpu_wb_conn->wb_enc, job);
> +
> +	return 0;
> +}
> +
> +static void dpu_wb_conn_cleanup_job(struct drm_writeback_connector *connector,
> +		struct drm_writeback_job *job)
> +{
> +	struct dpu_wb_connector *dpu_wb_conn = to_dpu_wb_conn(connector);
> +
> +	if (!job->fb)
> +		return;
> +
> +	dpu_encoder_cleanup_wb_job(dpu_wb_conn->wb_enc, job);
> +}
> +
> +static const struct drm_connector_helper_funcs dpu_wb_conn_helper_funcs = {
> +	.get_modes = dpu_wb_conn_get_modes,
> +	.prepare_writeback_job = dpu_wb_conn_prepare_job,
> +	.cleanup_writeback_job = dpu_wb_conn_cleanup_job,
> +};
> +
> +int dpu_writeback_init(struct drm_device *dev, struct drm_encoder *enc,
> +		const u32 *format_list, u32 num_formats)
> +{
> +	struct dpu_wb_connector *dpu_wb_conn;
> +	int rc = 0;
> +
> +	dpu_wb_conn = devm_kzalloc(dev->dev, sizeof(*dpu_wb_conn), GFP_KERNEL);
> +
> +	drm_connector_helper_add(&dpu_wb_conn->base.base, &dpu_wb_conn_helper_funcs);
> +
> +	/* DPU initializes the encoder and sets it up completely for writeback
> +	 * cases and hence should use the new API drm_writeback_connector_init_with_encoder
> +	 * to initialize the writeback connector
> +	 */
> +	rc = drm_writeback_connector_init_with_encoder(dev, &dpu_wb_conn->base, enc,
> +			&dpu_wb_conn_funcs, format_list, num_formats);
> +
> +	if (!rc)
> +		dpu_wb_conn->wb_enc = enc;
> +
> +	return rc;
> +}
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.h
> new file mode 100644
> index 0000000..5a75ea9
> --- /dev/null
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_writeback.h
> @@ -0,0 +1,31 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
> + */
> +
> +#ifndef _DPU_WRITEBACK_H
> +#define _DPU_WRITEBACK_H
> +
> +#include <drm/drm_crtc.h>
> +#include <drm/drm_file.h>
> +#include <drm/drm_probe_helper.h>
> +#include <drm/drm_writeback.h>
> +
> +#include "msm_drv.h"
> +#include "dpu_kms.h"
> +#include "dpu_encoder_phys.h"
> +
> +struct dpu_wb_connector {
> +	struct drm_writeback_connector base;
> +	struct drm_encoder *wb_enc;
> +};
> +
> +static inline struct dpu_wb_connector *to_dpu_wb_conn(struct drm_writeback_connector *conn)
> +{
> +	return container_of(conn, struct dpu_wb_connector, base);
> +}
> +
> +int dpu_writeback_init(struct drm_device *dev, struct drm_encoder *enc,
> +		const u32 *format_list, u32 num_formats);
> +
> +#endif /*_DPU_WRITEBACK_H */


-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v5 10/19] drm/msm/dpu: make changes to dpu_encoder to support virtual encoder
  2022-04-25  0:32 ` [PATCH v5 10/19] drm/msm/dpu: make changes to dpu_encoder to support virtual encoder Abhinav Kumar
@ 2022-04-26  0:21   ` Dmitry Baryshkov
  2022-04-26  0:44     ` Abhinav Kumar
  0 siblings, 1 reply; 29+ messages in thread
From: Dmitry Baryshkov @ 2022-04-26  0:21 UTC (permalink / raw)
  To: Abhinav Kumar, freedreno
  Cc: markyacoub, liviu.dudau, dri-devel, swboyd, seanpaul,
	laurent.pinchart, quic_jesszhan, quic_aravindh

On 25/04/2022 03:32, Abhinav Kumar wrote:
> Make changes to dpu_encoder to support virtual encoder needed
> to support writeback for dpu.
> 
> changes in v4:
> 	- squash dpu_encoder pieces from [1]
> 
> [1] https://patchwork.freedesktop.org/patch/483099/?series=102964&rev=2
> 
> Signed-off-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
> ---
>   drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c      | 94 +++++++++++++++++++-----
>   drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h |  7 ++
>   2 files changed, 83 insertions(+), 18 deletions(-)
> 
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> index 25c7eda..d1e92d89 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> @@ -1013,9 +1013,18 @@ static void dpu_encoder_virt_atomic_mode_set(struct drm_encoder *drm_enc,
>   		if (phys->intf_idx >= INTF_0 && phys->intf_idx < INTF_MAX)
>   			phys->hw_intf = dpu_rm_get_intf(&dpu_kms->rm, phys->intf_idx);
>   
> -		if (!phys->hw_intf) {
> +		if (phys->wb_idx >= WB_0 && phys->wb_idx < WB_MAX)
> +			phys->hw_wb = dpu_rm_get_wb(&dpu_kms->rm, phys->wb_idx);
> +
> +		if (!phys->hw_intf && !phys->hw_wb) {
>   			DPU_ERROR_ENC(dpu_enc,
> -				      "no intf block assigned at idx: %d\n", i);
> +				      "no intf or wb block assigned at idx: %d\n", i);
> +			return;
> +		}
> +
> +		if (phys->hw_intf && phys->hw_wb) {
> +			DPU_ERROR_ENC(dpu_enc,
> +					"invalid phys both intf and wb block at idx: %d\n", i);
>   			return;
>   		}
>   
> @@ -1163,16 +1172,35 @@ static enum dpu_intf dpu_encoder_get_intf(struct dpu_mdss_cfg *catalog,
>   {
>   	int i = 0;
>   
> -	for (i = 0; i < catalog->intf_count; i++) {
> -		if (catalog->intf[i].type == type
> -		    && catalog->intf[i].controller_id == controller_id) {
> -			return catalog->intf[i].id;
> +	if (type != INTF_WB) {
> +		for (i = 0; i < catalog->intf_count; i++) {
> +			if (catalog->intf[i].type == type
> +				&& catalog->intf[i].controller_id == controller_id) {
> +				return catalog->intf[i].id;
> +			}
>   		}
>   	}
>   
>   	return INTF_MAX;
>   }
>   
> +static enum dpu_wb dpu_encoder_get_wb(struct dpu_mdss_cfg *catalog,
> +		enum dpu_intf_type type, u32 controller_id)
> +{
> +	int i = 0;
> +
> +	if (type != INTF_WB)
> +		goto end;
> +
> +	for (i = 0; i < catalog->wb_count; i++) {
> +		if (catalog->wb[i].id == controller_id)
> +			return catalog->wb[i].id;
> +	}
> +
> +end:
> +	return WB_MAX;
> +}
> +
>   static void dpu_encoder_vblank_callback(struct drm_encoder *drm_enc,
>   		struct dpu_encoder_phys *phy_enc)
>   {
> @@ -1887,16 +1915,32 @@ void dpu_encoder_helper_phys_cleanup(struct dpu_encoder_phys *phys_enc)
>   
>   	dpu_encoder_helper_reset_mixers(phys_enc);
>   
> -	for (i = 0; i < dpu_enc->num_phys_encs; i++) {
> -		if (dpu_enc->phys_encs[i] && phys_enc->hw_intf->ops.bind_pingpong_blk)
> -			phys_enc->hw_intf->ops.bind_pingpong_blk(
> -					dpu_enc->phys_encs[i]->hw_intf, false,
> -					dpu_enc->phys_encs[i]->hw_pp->idx);
> -
> -		/* mark INTF flush as pending */
> -		if (phys_enc->hw_ctl->ops.update_pending_flush_intf)
> -			phys_enc->hw_ctl->ops.update_pending_flush_intf(phys_enc->hw_ctl,
> -					dpu_enc->phys_encs[i]->hw_intf->idx);
> +	/*
> +	 * TODO: move the once-only operation like CTL flush/trigger
> +	 * into dpu_encoder_virt_disable() and all operations which need
> +	 * to be done per phys encoder into the phys_disable() op.
> +	 */
> +	if (phys_enc->hw_wb) {
> +		/* disable the PP block */
> +		if (phys_enc->hw_wb->ops.bind_pingpong_blk)
> +			phys_enc->hw_wb->ops.bind_pingpong_blk(phys_enc->hw_wb, false,
> +					phys_enc->hw_pp->idx);
> +
> +		/* mark WB flush as pending */
> +		if (phys_enc->hw_ctl->ops.update_pending_flush_wb)
> +			phys_enc->hw_ctl->ops.update_pending_flush_wb(ctl, phys_enc->hw_wb->idx);
> +	} else {
> +		for (i = 0; i < dpu_enc->num_phys_encs; i++) {
> +			if (dpu_enc->phys_encs[i] && phys_enc->hw_intf->ops.bind_pingpong_blk)
> +				phys_enc->hw_intf->ops.bind_pingpong_blk(
> +						dpu_enc->phys_encs[i]->hw_intf, false,
> +						dpu_enc->phys_encs[i]->hw_pp->idx);
> +
> +			/* mark INTF flush as pending */
> +			if (phys_enc->hw_ctl->ops.update_pending_flush_intf)
> +				phys_enc->hw_ctl->ops.update_pending_flush_intf(phys_enc->hw_ctl,
> +						dpu_enc->phys_encs[i]->hw_intf->idx);
> +		}
>   	}
>   
>   	/* reset the merge 3D HW block */
> @@ -2112,6 +2156,9 @@ static int dpu_encoder_setup_display(struct dpu_encoder_virt *dpu_enc,
>   	case DRM_MODE_ENCODER_TMDS:
>   		intf_type = INTF_DP;
>   		break;
> +	case DRM_MODE_ENCODER_VIRTUAL:
> +		intf_type = INTF_WB;
> +		break;
>   	}
>   
>   	WARN_ON(disp_info->num_of_h_tiles < 1);
> @@ -2149,8 +2196,19 @@ static int dpu_encoder_setup_display(struct dpu_encoder_virt *dpu_enc,
>   		phys_params.intf_idx = dpu_encoder_get_intf(dpu_kms->catalog,
>   													intf_type,
>   													controller_id);
> -		if (phys_params.intf_idx == INTF_MAX) {
> -			DPU_ERROR_ENC(dpu_enc, "could not get intf: type %d, id %d\n",
> +
> +		phys_params.wb_idx = dpu_encoder_get_wb(dpu_kms->catalog,
> +				intf_type, controller_id);
> +		/*
> +		 * For boards which have no physical displays, having no interface
> +		 * is fine because it can still be used with just writeback.
> +		 * If we try without a display on a board which uses a DPU in which
> +		 * writeback is not supported, then this will still fail as it will not
> +		 * find any writeback in the catalog.
> +		 */
> +		if ((phys_params.intf_idx == INTF_MAX) &&
> +				(phys_params.wb_idx == WB_MAX)) {
> +			DPU_ERROR_ENC(dpu_enc, "could not get intf or wb: type %d, id %d\n",

I've commented the previous iteration by the mistake, but the comment 
still applies to this version too. Let's repeat it, so that we have all 
the comments in the single version.

I think the comment is misleading. It is a phys_params, so it must have
etiher intf_idx or wb_idx, but not both of them, despite the board
having the interfaces or WB.

So somthing like this might be more appropriate:

/*
   * The phys_params might represent either an INTF or a WB unit, but not
   * both of them at the same time.
   */

if ((phys_params.intf_idx == INTF_MAX) && (phys_params.wb_idx == WB_MAX)) {
   .... // error out
}

if ((phys_params.intf_idx != INTF_MAX) && (phys_params.wb_idx == WB_MAX)) {
    ........ // error out
}


Looks good otherwise.


>   						  intf_type, controller_id);
>   			ret = -EINVAL;
>   		}
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
> index 544a9a4..c84b8e8 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
> @@ -11,6 +11,7 @@
>   
>   #include "dpu_kms.h"
>   #include "dpu_hw_intf.h"
> +#include "dpu_hw_wb.h"
>   #include "dpu_hw_pingpong.h"
>   #include "dpu_hw_ctl.h"
>   #include "dpu_hw_top.h"
> @@ -165,12 +166,14 @@ enum dpu_intr_idx {
>    * @hw_ctl:		Hardware interface to the ctl registers
>    * @hw_pp:		Hardware interface to the ping pong registers
>    * @hw_intf:		Hardware interface to the intf registers
> + * @hw_wb:		Hardware interface to the wb registers
>    * @dpu_kms:		Pointer to the dpu_kms top level
>    * @cached_mode:	DRM mode cached at mode_set time, acted on in enable
>    * @enabled:		Whether the encoder has enabled and running a mode
>    * @split_role:		Role to play in a split-panel configuration
>    * @intf_mode:		Interface mode
>    * @intf_idx:		Interface index on dpu hardware
> + * @wb_idx:			Writeback index on dpu hardware
>    * @enc_spinlock:	Virtual-Encoder-Wide Spin Lock for IRQ purposes
>    * @enable_state:	Enable state tracking
>    * @vblank_refcount:	Reference count of vblank request
> @@ -193,11 +196,13 @@ struct dpu_encoder_phys {
>   	struct dpu_hw_ctl *hw_ctl;
>   	struct dpu_hw_pingpong *hw_pp;
>   	struct dpu_hw_intf *hw_intf;
> +	struct dpu_hw_wb *hw_wb;
>   	struct dpu_kms *dpu_kms;
>   	struct drm_display_mode cached_mode;
>   	enum dpu_enc_split_role split_role;
>   	enum dpu_intf_mode intf_mode;
>   	enum dpu_intf intf_idx;
> +	enum dpu_wb wb_idx;
>   	spinlock_t *enc_spinlock;
>   	enum dpu_enc_enable_state enable_state;
>   	atomic_t vblank_refcount;
> @@ -243,6 +248,7 @@ struct dpu_encoder_phys_cmd {
>    * @parent_ops:		Callbacks exposed by the parent to the phys_enc
>    * @split_role:		Role to play in a split-panel configuration
>    * @intf_idx:		Interface index this phys_enc will control
> + * @wb_idx:			Writeback index this phys_enc will control
>    * @enc_spinlock:	Virtual-Encoder-Wide Spin Lock for IRQ purposes
>    */
>   struct dpu_enc_phys_init_params {
> @@ -251,6 +257,7 @@ struct dpu_enc_phys_init_params {
>   	const struct dpu_encoder_virt_ops *parent_ops;
>   	enum dpu_enc_split_role split_role;
>   	enum dpu_intf intf_idx;
> +	enum dpu_wb wb_idx;
>   	spinlock_t *enc_spinlock;
>   };
>   


-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v5 15/19] drm/msm/dpu: initialize dpu encoder and connector for writeback
  2022-04-25  0:32 ` [PATCH v5 15/19] drm/msm/dpu: initialize dpu encoder and connector for writeback Abhinav Kumar
@ 2022-04-26  0:32   ` Laurent Pinchart
  2022-04-26  0:42     ` Abhinav Kumar
  2022-04-26  2:11     ` Dmitry Baryshkov
  0 siblings, 2 replies; 29+ messages in thread
From: Laurent Pinchart @ 2022-04-26  0:32 UTC (permalink / raw)
  To: Abhinav Kumar
  Cc: markyacoub, liviu.dudau, dri-devel, swboyd, seanpaul,
	dmitry.baryshkov, quic_jesszhan, quic_aravindh, freedreno

Hi Abhinav,

On Sun, Apr 24, 2022 at 05:32:06PM -0700, Abhinav Kumar wrote:
> Initialize dpu encoder and connector for writeback if the
> target supports it in the catalog.
> 
> changes in v2:
> 	- start initialing the encoder for writeback since we
> 	have migrated to using drm_writeback_connector_init_with_encoder()
> 	- instead of checking for WB_2 inside _dpu_kms_initialize_writeback
> 	call it only when its WB_2
> 	- rebase on tip of msm-next and remove usage of priv->encoders
> 
> changes in v3:
> 	- none
> 
> changes in v4:
> 	- fix copyright years order
> 
> Signed-off-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
> Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> ---
>  drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 27 +++++++++----
>  drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c     | 61 ++++++++++++++++++++++++++++-
>  2 files changed, 80 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> index 24870eb..2d79002 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> @@ -2102,7 +2102,7 @@ static void dpu_encoder_early_unregister(struct drm_encoder *encoder)
>  }
>  
>  static int dpu_encoder_virt_add_phys_encs(
> -		u32 display_caps,
> +		struct msm_display_info *disp_info,
>  		struct dpu_encoder_virt *dpu_enc,
>  		struct dpu_enc_phys_init_params *params)
>  {
> @@ -2121,7 +2121,7 @@ static int dpu_encoder_virt_add_phys_encs(
>  		return -EINVAL;
>  	}
>  
> -	if (display_caps & MSM_DISPLAY_CAP_VID_MODE) {
> +	if (disp_info->capabilities & MSM_DISPLAY_CAP_VID_MODE) {
>  		enc = dpu_encoder_phys_vid_init(params);
>  
>  		if (IS_ERR_OR_NULL(enc)) {
> @@ -2134,7 +2134,7 @@ static int dpu_encoder_virt_add_phys_encs(
>  		++dpu_enc->num_phys_encs;
>  	}
>  
> -	if (display_caps & MSM_DISPLAY_CAP_CMD_MODE) {
> +	if (disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) {
>  		enc = dpu_encoder_phys_cmd_init(params);
>  
>  		if (IS_ERR_OR_NULL(enc)) {
> @@ -2147,6 +2147,19 @@ static int dpu_encoder_virt_add_phys_encs(
>  		++dpu_enc->num_phys_encs;
>  	}
>  
> +	if (disp_info->intf_type == DRM_MODE_ENCODER_VIRTUAL) {
> +		enc = dpu_encoder_phys_wb_init(params);
> +
> +		if (IS_ERR_OR_NULL(enc)) {
> +			DPU_ERROR_ENC(dpu_enc, "failed to init wb enc: %ld\n",
> +					PTR_ERR(enc));
> +			return enc == NULL ? -EINVAL : PTR_ERR(enc);
> +		}
> +
> +		dpu_enc->phys_encs[dpu_enc->num_phys_encs] = enc;
> +		++dpu_enc->num_phys_encs;
> +	}
> +
>  	if (params->split_role == ENC_ROLE_SLAVE)
>  		dpu_enc->cur_slave = enc;
>  	else
> @@ -2248,9 +2261,8 @@ static int dpu_encoder_setup_display(struct dpu_encoder_virt *dpu_enc,
>  		}
>  
>  		if (!ret) {
> -			ret = dpu_encoder_virt_add_phys_encs(disp_info->capabilities,
> -												 dpu_enc,
> -												 &phys_params);
> +			ret = dpu_encoder_virt_add_phys_encs(disp_info,
> +					dpu_enc, &phys_params);
>  			if (ret)
>  				DPU_ERROR_ENC(dpu_enc, "failed to add phys encs\n");
>  		}
> @@ -2367,8 +2379,9 @@ struct drm_encoder *dpu_encoder_init(struct drm_device *dev,
>  	if (!dpu_enc)
>  		return ERR_PTR(-ENOMEM);
>  
> +
>  	rc = drm_encoder_init(dev, &dpu_enc->base, &dpu_encoder_funcs,
> -			drm_enc_mode, NULL);
> +							  drm_enc_mode, NULL);
>  	if (rc) {
>  		devm_kfree(dev->dev, dpu_enc);
>  		return ERR_PTR(rc);
> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
> index c683cab..9a406e1 100644
> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
> @@ -1,7 +1,9 @@
>  // SPDX-License-Identifier: GPL-2.0-only
>  /*
> - * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
>   * Copyright (C) 2013 Red Hat
> + * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
> + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
> + *
>   * Author: Rob Clark <robdclark@gmail.com>
>   */
>  
> @@ -15,6 +17,7 @@
>  #include <drm/drm_crtc.h>
>  #include <drm/drm_file.h>
>  #include <drm/drm_vblank.h>
> +#include <drm/drm_writeback.h>
>  
>  #include "msm_drv.h"
>  #include "msm_mmu.h"
> @@ -29,6 +32,7 @@
>  #include "dpu_kms.h"
>  #include "dpu_plane.h"
>  #include "dpu_vbif.h"
> +#include "dpu_writeback.h"
>  
>  #define CREATE_TRACE_POINTS
>  #include "dpu_trace.h"
> @@ -648,6 +652,45 @@ static int _dpu_kms_initialize_displayport(struct drm_device *dev,
>  	return 0;
>  }
>  
> +static int _dpu_kms_initialize_writeback(struct drm_device *dev,
> +		struct msm_drm_private *priv, struct dpu_kms *dpu_kms,
> +		const u32 *wb_formats, int n_formats)
> +{
> +	struct drm_encoder *encoder = NULL;
> +	struct msm_display_info info;
> +	int rc;
> +
> +	encoder = dpu_encoder_init(dev, DRM_MODE_ENCODER_VIRTUAL);

I'm puzzled. I thought the whole purpose of the
drm_writeback_connector_init_with_encoder() function was to share an
encoder between writeback and a real display output, but the encoder you
create here seems to be specific to writeback. What am I missing ?

> +	if (IS_ERR(encoder)) {
> +		DPU_ERROR("encoder init failed for dsi display\n");
> +		return PTR_ERR(encoder);
> +	}
> +
> +	memset(&info, 0, sizeof(info));
> +
> +	rc = dpu_writeback_init(dev, encoder, wb_formats,
> +			n_formats);
> +	if (rc) {
> +		DPU_ERROR("dpu_writeback_init, rc = %d\n", rc);
> +		drm_encoder_cleanup(encoder);
> +		return rc;
> +	}
> +
> +	info.num_of_h_tiles = 1;
> +	/* use only WB idx 2 instance for DPU */
> +	info.h_tile_instance[0] = WB_2;
> +	info.intf_type = encoder->encoder_type;
> +
> +	rc = dpu_encoder_setup(dev, encoder, &info);
> +	if (rc) {
> +		DPU_ERROR("failed to setup DPU encoder %d: rc:%d\n",
> +				  encoder->base.id, rc);
> +		return rc;
> +	}
> +
> +	return 0;
> +}
> +
>  /**
>   * _dpu_kms_setup_displays - create encoders, bridges and connectors
>   *                           for underlying displays
> @@ -661,6 +704,7 @@ static int _dpu_kms_setup_displays(struct drm_device *dev,
>  				    struct dpu_kms *dpu_kms)
>  {
>  	int rc = 0;
> +	int i;
>  
>  	rc = _dpu_kms_initialize_dsi(dev, priv, dpu_kms);
>  	if (rc) {
> @@ -674,6 +718,21 @@ static int _dpu_kms_setup_displays(struct drm_device *dev,
>  		return rc;
>  	}
>  
> +	/* Since WB isn't a driver check the catalog before initializing */
> +	if (dpu_kms->catalog->wb_count) {
> +		for (i = 0; i < dpu_kms->catalog->wb_count; i++) {
> +			if (dpu_kms->catalog->wb[i].id == WB_2) {
> +				rc = _dpu_kms_initialize_writeback(dev, priv, dpu_kms,
> +						dpu_kms->catalog->wb[i].format_list,
> +						dpu_kms->catalog->wb[i].num_formats);
> +				if (rc) {
> +					DPU_ERROR("initialize_WB failed, rc = %d\n", rc);
> +					return rc;
> +				}
> +			}
> +		}
> +	}
> +
>  	return rc;
>  }
>  

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v5 15/19] drm/msm/dpu: initialize dpu encoder and connector for writeback
  2022-04-26  0:32   ` Laurent Pinchart
@ 2022-04-26  0:42     ` Abhinav Kumar
  2022-04-26  2:11     ` Dmitry Baryshkov
  1 sibling, 0 replies; 29+ messages in thread
From: Abhinav Kumar @ 2022-04-26  0:42 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: markyacoub, liviu.dudau, dri-devel, swboyd, seanpaul,
	dmitry.baryshkov, quic_jesszhan, quic_aravindh, freedreno

Hi Laurent

On 4/25/2022 5:32 PM, Laurent Pinchart wrote:
> Hi Abhinav,
> 
> On Sun, Apr 24, 2022 at 05:32:06PM -0700, Abhinav Kumar wrote:
>> Initialize dpu encoder and connector for writeback if the
>> target supports it in the catalog.
>>
>> changes in v2:
>> 	- start initialing the encoder for writeback since we
>> 	have migrated to using drm_writeback_connector_init_with_encoder()
>> 	- instead of checking for WB_2 inside _dpu_kms_initialize_writeback
>> 	call it only when its WB_2
>> 	- rebase on tip of msm-next and remove usage of priv->encoders
>>
>> changes in v3:
>> 	- none
>>
>> changes in v4:
>> 	- fix copyright years order
>>
>> Signed-off-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
>> Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>> ---
>>   drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 27 +++++++++----
>>   drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c     | 61 ++++++++++++++++++++++++++++-
>>   2 files changed, 80 insertions(+), 8 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
>> index 24870eb..2d79002 100644
>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
>> @@ -2102,7 +2102,7 @@ static void dpu_encoder_early_unregister(struct drm_encoder *encoder)
>>   }
>>   
>>   static int dpu_encoder_virt_add_phys_encs(
>> -		u32 display_caps,
>> +		struct msm_display_info *disp_info,
>>   		struct dpu_encoder_virt *dpu_enc,
>>   		struct dpu_enc_phys_init_params *params)
>>   {
>> @@ -2121,7 +2121,7 @@ static int dpu_encoder_virt_add_phys_encs(
>>   		return -EINVAL;
>>   	}
>>   
>> -	if (display_caps & MSM_DISPLAY_CAP_VID_MODE) {
>> +	if (disp_info->capabilities & MSM_DISPLAY_CAP_VID_MODE) {
>>   		enc = dpu_encoder_phys_vid_init(params);
>>   
>>   		if (IS_ERR_OR_NULL(enc)) {
>> @@ -2134,7 +2134,7 @@ static int dpu_encoder_virt_add_phys_encs(
>>   		++dpu_enc->num_phys_encs;
>>   	}
>>   
>> -	if (display_caps & MSM_DISPLAY_CAP_CMD_MODE) {
>> +	if (disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) {
>>   		enc = dpu_encoder_phys_cmd_init(params);
>>   
>>   		if (IS_ERR_OR_NULL(enc)) {
>> @@ -2147,6 +2147,19 @@ static int dpu_encoder_virt_add_phys_encs(
>>   		++dpu_enc->num_phys_encs;
>>   	}
>>   
>> +	if (disp_info->intf_type == DRM_MODE_ENCODER_VIRTUAL) {
>> +		enc = dpu_encoder_phys_wb_init(params);
>> +
>> +		if (IS_ERR_OR_NULL(enc)) {
>> +			DPU_ERROR_ENC(dpu_enc, "failed to init wb enc: %ld\n",
>> +					PTR_ERR(enc));
>> +			return enc == NULL ? -EINVAL : PTR_ERR(enc);
>> +		}
>> +
>> +		dpu_enc->phys_encs[dpu_enc->num_phys_encs] = enc;
>> +		++dpu_enc->num_phys_encs;
>> +	}
>> +
>>   	if (params->split_role == ENC_ROLE_SLAVE)
>>   		dpu_enc->cur_slave = enc;
>>   	else
>> @@ -2248,9 +2261,8 @@ static int dpu_encoder_setup_display(struct dpu_encoder_virt *dpu_enc,
>>   		}
>>   
>>   		if (!ret) {
>> -			ret = dpu_encoder_virt_add_phys_encs(disp_info->capabilities,
>> -												 dpu_enc,
>> -												 &phys_params);
>> +			ret = dpu_encoder_virt_add_phys_encs(disp_info,
>> +					dpu_enc, &phys_params);
>>   			if (ret)
>>   				DPU_ERROR_ENC(dpu_enc, "failed to add phys encs\n");
>>   		}
>> @@ -2367,8 +2379,9 @@ struct drm_encoder *dpu_encoder_init(struct drm_device *dev,
>>   	if (!dpu_enc)
>>   		return ERR_PTR(-ENOMEM);
>>   
>> +
>>   	rc = drm_encoder_init(dev, &dpu_enc->base, &dpu_encoder_funcs,
>> -			drm_enc_mode, NULL);
>> +							  drm_enc_mode, NULL);
>>   	if (rc) {
>>   		devm_kfree(dev->dev, dpu_enc);
>>   		return ERR_PTR(rc);
>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
>> index c683cab..9a406e1 100644
>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
>> @@ -1,7 +1,9 @@
>>   // SPDX-License-Identifier: GPL-2.0-only
>>   /*
>> - * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
>>    * Copyright (C) 2013 Red Hat
>> + * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
>> + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
>> + *
>>    * Author: Rob Clark <robdclark@gmail.com>
>>    */
>>   
>> @@ -15,6 +17,7 @@
>>   #include <drm/drm_crtc.h>
>>   #include <drm/drm_file.h>
>>   #include <drm/drm_vblank.h>
>> +#include <drm/drm_writeback.h>
>>   
>>   #include "msm_drv.h"
>>   #include "msm_mmu.h"
>> @@ -29,6 +32,7 @@
>>   #include "dpu_kms.h"
>>   #include "dpu_plane.h"
>>   #include "dpu_vbif.h"
>> +#include "dpu_writeback.h"
>>   
>>   #define CREATE_TRACE_POINTS
>>   #include "dpu_trace.h"
>> @@ -648,6 +652,45 @@ static int _dpu_kms_initialize_displayport(struct drm_device *dev,
>>   	return 0;
>>   }
>>   
>> +static int _dpu_kms_initialize_writeback(struct drm_device *dev,
>> +		struct msm_drm_private *priv, struct dpu_kms *dpu_kms,
>> +		const u32 *wb_formats, int n_formats)
>> +{
>> +	struct drm_encoder *encoder = NULL;
>> +	struct msm_display_info info;
>> +	int rc;
>> +
>> +	encoder = dpu_encoder_init(dev, DRM_MODE_ENCODER_VIRTUAL);
> 
> I'm puzzled. I thought the whole purpose of the
> drm_writeback_connector_init_with_encoder() function was to share an
> encoder between writeback and a real display output, but the encoder you
> create here seems to be specific to writeback. What am I missing ?

There are two purposes as I had written:


"For vendors drivers which pass an already allocated and
initialized encoder especially for cases where the encoder
hardware is shared OR the writeback encoder shares the resources
with the rest of the display pipeline introduce a new API"

1) To share the display hardware such as clocks/interrupts between our 
display hardware

And yes, if you observe, our DPU writeback encoder shares the hardware 
functionality for those pieces in dpu_encoder. So it is a real encoder.

2) To share an encoder between writeback and real display output.

This series will be slowly extended to support that encoder as well.

This is the first series which adds basic writeback support to our 
driver only for one DPU chipset sm8250.

https://patchwork.freedesktop.org/patch/483218/?series=99724&rev=5

Our hardware also supports the functionality of sharing the encoder 
between writeback and real display output.

I will add that on top of this.

In older chipsets also, where the encoder will be shared will again have 
to supported on top of this series.

So this is just the first series to add support, we will keep building 
on top of this to add support for multiple chipsets which will cover all 
the cases I explained why we need this.

Thanks

Abhinav
> 
>> +	if (IS_ERR(encoder)) {
>> +		DPU_ERROR("encoder init failed for dsi display\n");
>> +		return PTR_ERR(encoder);
>> +	}
>> +
>> +	memset(&info, 0, sizeof(info));
>> +
>> +	rc = dpu_writeback_init(dev, encoder, wb_formats,
>> +			n_formats);
>> +	if (rc) {
>> +		DPU_ERROR("dpu_writeback_init, rc = %d\n", rc);
>> +		drm_encoder_cleanup(encoder);
>> +		return rc;
>> +	}
>> +
>> +	info.num_of_h_tiles = 1;
>> +	/* use only WB idx 2 instance for DPU */
>> +	info.h_tile_instance[0] = WB_2;
>> +	info.intf_type = encoder->encoder_type;
>> +
>> +	rc = dpu_encoder_setup(dev, encoder, &info);
>> +	if (rc) {
>> +		DPU_ERROR("failed to setup DPU encoder %d: rc:%d\n",
>> +				  encoder->base.id, rc);
>> +		return rc;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>>   /**
>>    * _dpu_kms_setup_displays - create encoders, bridges and connectors
>>    *                           for underlying displays
>> @@ -661,6 +704,7 @@ static int _dpu_kms_setup_displays(struct drm_device *dev,
>>   				    struct dpu_kms *dpu_kms)
>>   {
>>   	int rc = 0;
>> +	int i;
>>   
>>   	rc = _dpu_kms_initialize_dsi(dev, priv, dpu_kms);
>>   	if (rc) {
>> @@ -674,6 +718,21 @@ static int _dpu_kms_setup_displays(struct drm_device *dev,
>>   		return rc;
>>   	}
>>   
>> +	/* Since WB isn't a driver check the catalog before initializing */
>> +	if (dpu_kms->catalog->wb_count) {
>> +		for (i = 0; i < dpu_kms->catalog->wb_count; i++) {
>> +			if (dpu_kms->catalog->wb[i].id == WB_2) {
>> +				rc = _dpu_kms_initialize_writeback(dev, priv, dpu_kms,
>> +						dpu_kms->catalog->wb[i].format_list,
>> +						dpu_kms->catalog->wb[i].num_formats);
>> +				if (rc) {
>> +					DPU_ERROR("initialize_WB failed, rc = %d\n", rc);
>> +					return rc;
>> +				}
>> +			}
>> +		}
>> +	}
>> +
>>   	return rc;
>>   }
>>   
> 

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v5 10/19] drm/msm/dpu: make changes to dpu_encoder to support virtual encoder
  2022-04-26  0:21   ` Dmitry Baryshkov
@ 2022-04-26  0:44     ` Abhinav Kumar
  2022-04-26  0:46       ` Dmitry Baryshkov
  0 siblings, 1 reply; 29+ messages in thread
From: Abhinav Kumar @ 2022-04-26  0:44 UTC (permalink / raw)
  To: Dmitry Baryshkov, freedreno
  Cc: markyacoub, liviu.dudau, dri-devel, swboyd, seanpaul,
	laurent.pinchart, quic_jesszhan, quic_aravindh

Hi Dmitry

On 4/25/2022 5:21 PM, Dmitry Baryshkov wrote:
> On 25/04/2022 03:32, Abhinav Kumar wrote:
>> Make changes to dpu_encoder to support virtual encoder needed
>> to support writeback for dpu.
>>
>> changes in v4:
>>     - squash dpu_encoder pieces from [1]
>>
>> [1] https://patchwork.freedesktop.org/patch/483099/?series=102964&rev=2
>>
>> Signed-off-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
>> ---
>>   drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c      | 94 
>> +++++++++++++++++++-----
>>   drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h |  7 ++
>>   2 files changed, 83 insertions(+), 18 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
>> b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
>> index 25c7eda..d1e92d89 100644
>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
>> @@ -1013,9 +1013,18 @@ static void 
>> dpu_encoder_virt_atomic_mode_set(struct drm_encoder *drm_enc,
>>           if (phys->intf_idx >= INTF_0 && phys->intf_idx < INTF_MAX)
>>               phys->hw_intf = dpu_rm_get_intf(&dpu_kms->rm, 
>> phys->intf_idx);
>> -        if (!phys->hw_intf) {
>> +        if (phys->wb_idx >= WB_0 && phys->wb_idx < WB_MAX)
>> +            phys->hw_wb = dpu_rm_get_wb(&dpu_kms->rm, phys->wb_idx);
>> +
>> +        if (!phys->hw_intf && !phys->hw_wb) {
>>               DPU_ERROR_ENC(dpu_enc,
>> -                      "no intf block assigned at idx: %d\n", i);
>> +                      "no intf or wb block assigned at idx: %d\n", i);
>> +            return;
>> +        }
>> +
>> +        if (phys->hw_intf && phys->hw_wb) {
>> +            DPU_ERROR_ENC(dpu_enc,
>> +                    "invalid phys both intf and wb block at idx: 
>> %d\n", i);
>>               return;
>>           }
>> @@ -1163,16 +1172,35 @@ static enum dpu_intf 
>> dpu_encoder_get_intf(struct dpu_mdss_cfg *catalog,
>>   {
>>       int i = 0;
>> -    for (i = 0; i < catalog->intf_count; i++) {
>> -        if (catalog->intf[i].type == type
>> -            && catalog->intf[i].controller_id == controller_id) {
>> -            return catalog->intf[i].id;
>> +    if (type != INTF_WB) {
>> +        for (i = 0; i < catalog->intf_count; i++) {
>> +            if (catalog->intf[i].type == type
>> +                && catalog->intf[i].controller_id == controller_id) {
>> +                return catalog->intf[i].id;
>> +            }
>>           }
>>       }
>>       return INTF_MAX;
>>   }
>> +static enum dpu_wb dpu_encoder_get_wb(struct dpu_mdss_cfg *catalog,
>> +        enum dpu_intf_type type, u32 controller_id)
>> +{
>> +    int i = 0;
>> +
>> +    if (type != INTF_WB)
>> +        goto end;
>> +
>> +    for (i = 0; i < catalog->wb_count; i++) {
>> +        if (catalog->wb[i].id == controller_id)
>> +            return catalog->wb[i].id;
>> +    }
>> +
>> +end:
>> +    return WB_MAX;
>> +}
>> +
>>   static void dpu_encoder_vblank_callback(struct drm_encoder *drm_enc,
>>           struct dpu_encoder_phys *phy_enc)
>>   {
>> @@ -1887,16 +1915,32 @@ void dpu_encoder_helper_phys_cleanup(struct 
>> dpu_encoder_phys *phys_enc)
>>       dpu_encoder_helper_reset_mixers(phys_enc);
>> -    for (i = 0; i < dpu_enc->num_phys_encs; i++) {
>> -        if (dpu_enc->phys_encs[i] && 
>> phys_enc->hw_intf->ops.bind_pingpong_blk)
>> -            phys_enc->hw_intf->ops.bind_pingpong_blk(
>> -                    dpu_enc->phys_encs[i]->hw_intf, false,
>> -                    dpu_enc->phys_encs[i]->hw_pp->idx);
>> -
>> -        /* mark INTF flush as pending */
>> -        if (phys_enc->hw_ctl->ops.update_pending_flush_intf)
>> -            
>> phys_enc->hw_ctl->ops.update_pending_flush_intf(phys_enc->hw_ctl,
>> -                    dpu_enc->phys_encs[i]->hw_intf->idx);
>> +    /*
>> +     * TODO: move the once-only operation like CTL flush/trigger
>> +     * into dpu_encoder_virt_disable() and all operations which need
>> +     * to be done per phys encoder into the phys_disable() op.
>> +     */
>> +    if (phys_enc->hw_wb) {
>> +        /* disable the PP block */
>> +        if (phys_enc->hw_wb->ops.bind_pingpong_blk)
>> +            phys_enc->hw_wb->ops.bind_pingpong_blk(phys_enc->hw_wb, 
>> false,
>> +                    phys_enc->hw_pp->idx);
>> +
>> +        /* mark WB flush as pending */
>> +        if (phys_enc->hw_ctl->ops.update_pending_flush_wb)
>> +            phys_enc->hw_ctl->ops.update_pending_flush_wb(ctl, 
>> phys_enc->hw_wb->idx);
>> +    } else {
>> +        for (i = 0; i < dpu_enc->num_phys_encs; i++) {
>> +            if (dpu_enc->phys_encs[i] && 
>> phys_enc->hw_intf->ops.bind_pingpong_blk)
>> +                phys_enc->hw_intf->ops.bind_pingpong_blk(
>> +                        dpu_enc->phys_encs[i]->hw_intf, false,
>> +                        dpu_enc->phys_encs[i]->hw_pp->idx);
>> +
>> +            /* mark INTF flush as pending */
>> +            if (phys_enc->hw_ctl->ops.update_pending_flush_intf)
>> +                
>> phys_enc->hw_ctl->ops.update_pending_flush_intf(phys_enc->hw_ctl,
>> +                        dpu_enc->phys_encs[i]->hw_intf->idx);
>> +        }
>>       }
>>       /* reset the merge 3D HW block */
>> @@ -2112,6 +2156,9 @@ static int dpu_encoder_setup_display(struct 
>> dpu_encoder_virt *dpu_enc,
>>       case DRM_MODE_ENCODER_TMDS:
>>           intf_type = INTF_DP;
>>           break;
>> +    case DRM_MODE_ENCODER_VIRTUAL:
>> +        intf_type = INTF_WB;
>> +        break;
>>       }
>>       WARN_ON(disp_info->num_of_h_tiles < 1);
>> @@ -2149,8 +2196,19 @@ static int dpu_encoder_setup_display(struct 
>> dpu_encoder_virt *dpu_enc,
>>           phys_params.intf_idx = dpu_encoder_get_intf(dpu_kms->catalog,
>>                                                       intf_type,
>>                                                       controller_id);
>> -        if (phys_params.intf_idx == INTF_MAX) {
>> -            DPU_ERROR_ENC(dpu_enc, "could not get intf: type %d, id 
>> %d\n",
>> +
>> +        phys_params.wb_idx = dpu_encoder_get_wb(dpu_kms->catalog,
>> +                intf_type, controller_id);
>> +        /*
>> +         * For boards which have no physical displays, having no 
>> interface
>> +         * is fine because it can still be used with just writeback.
>> +         * If we try without a display on a board which uses a DPU in 
>> which
>> +         * writeback is not supported, then this will still fail as 
>> it will not
>> +         * find any writeback in the catalog.
>> +         */
>> +        if ((phys_params.intf_idx == INTF_MAX) &&
>> +                (phys_params.wb_idx == WB_MAX)) {
>> +            DPU_ERROR_ENC(dpu_enc, "could not get intf or wb: type 
>> %d, id %d\n",
> 
> I've commented the previous iteration by the mistake, but the comment 
> still applies to this version too. Let's repeat it, so that we have all 
> the comments in the single version.
> 
> I think the comment is misleading. It is a phys_params, so it must have
> etiher intf_idx or wb_idx, but not both of them, despite the board
> having the interfaces or WB.
> 
> So somthing like this might be more appropriate:
> 
> /*
>    * The phys_params might represent either an INTF or a WB unit, but not
>    * both of them at the same time.
>    */
> 
> if ((phys_params.intf_idx == INTF_MAX) && (phys_params.wb_idx == WB_MAX)) {
>    .... // error out
> }
> 
> if ((phys_params.intf_idx != INTF_MAX) && (phys_params.wb_idx == WB_MAX)) {
>     ........ // error out
> }

I didnt understand this condition. So if there is a valid intf but not 
valid wb intf, why is that an error.

> 
> 
> Looks good otherwise.
> 
> 
>>                             intf_type, controller_id);
>>               ret = -EINVAL;
>>           }
>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h 
>> b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
>> index 544a9a4..c84b8e8 100644
>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
>> @@ -11,6 +11,7 @@
>>   #include "dpu_kms.h"
>>   #include "dpu_hw_intf.h"
>> +#include "dpu_hw_wb.h"
>>   #include "dpu_hw_pingpong.h"
>>   #include "dpu_hw_ctl.h"
>>   #include "dpu_hw_top.h"
>> @@ -165,12 +166,14 @@ enum dpu_intr_idx {
>>    * @hw_ctl:        Hardware interface to the ctl registers
>>    * @hw_pp:        Hardware interface to the ping pong registers
>>    * @hw_intf:        Hardware interface to the intf registers
>> + * @hw_wb:        Hardware interface to the wb registers
>>    * @dpu_kms:        Pointer to the dpu_kms top level
>>    * @cached_mode:    DRM mode cached at mode_set time, acted on in 
>> enable
>>    * @enabled:        Whether the encoder has enabled and running a mode
>>    * @split_role:        Role to play in a split-panel configuration
>>    * @intf_mode:        Interface mode
>>    * @intf_idx:        Interface index on dpu hardware
>> + * @wb_idx:            Writeback index on dpu hardware
>>    * @enc_spinlock:    Virtual-Encoder-Wide Spin Lock for IRQ purposes
>>    * @enable_state:    Enable state tracking
>>    * @vblank_refcount:    Reference count of vblank request
>> @@ -193,11 +196,13 @@ struct dpu_encoder_phys {
>>       struct dpu_hw_ctl *hw_ctl;
>>       struct dpu_hw_pingpong *hw_pp;
>>       struct dpu_hw_intf *hw_intf;
>> +    struct dpu_hw_wb *hw_wb;
>>       struct dpu_kms *dpu_kms;
>>       struct drm_display_mode cached_mode;
>>       enum dpu_enc_split_role split_role;
>>       enum dpu_intf_mode intf_mode;
>>       enum dpu_intf intf_idx;
>> +    enum dpu_wb wb_idx;
>>       spinlock_t *enc_spinlock;
>>       enum dpu_enc_enable_state enable_state;
>>       atomic_t vblank_refcount;
>> @@ -243,6 +248,7 @@ struct dpu_encoder_phys_cmd {
>>    * @parent_ops:        Callbacks exposed by the parent to the phys_enc
>>    * @split_role:        Role to play in a split-panel configuration
>>    * @intf_idx:        Interface index this phys_enc will control
>> + * @wb_idx:            Writeback index this phys_enc will control
>>    * @enc_spinlock:    Virtual-Encoder-Wide Spin Lock for IRQ purposes
>>    */
>>   struct dpu_enc_phys_init_params {
>> @@ -251,6 +257,7 @@ struct dpu_enc_phys_init_params {
>>       const struct dpu_encoder_virt_ops *parent_ops;
>>       enum dpu_enc_split_role split_role;
>>       enum dpu_intf intf_idx;
>> +    enum dpu_wb wb_idx;
>>       spinlock_t *enc_spinlock;
>>   };
> 
> 

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v5 10/19] drm/msm/dpu: make changes to dpu_encoder to support virtual encoder
  2022-04-26  0:44     ` Abhinav Kumar
@ 2022-04-26  0:46       ` Dmitry Baryshkov
  0 siblings, 0 replies; 29+ messages in thread
From: Dmitry Baryshkov @ 2022-04-26  0:46 UTC (permalink / raw)
  To: Abhinav Kumar, freedreno
  Cc: markyacoub, liviu.dudau, dri-devel, swboyd, seanpaul,
	laurent.pinchart, quic_jesszhan, quic_aravindh

On 26/04/2022 03:44, Abhinav Kumar wrote:
> Hi Dmitry
> 
> On 4/25/2022 5:21 PM, Dmitry Baryshkov wrote:
>> On 25/04/2022 03:32, Abhinav Kumar wrote:
>>> Make changes to dpu_encoder to support virtual encoder needed
>>> to support writeback for dpu.
>>>
>>> changes in v4:
>>>     - squash dpu_encoder pieces from [1]
>>>
>>> [1] https://patchwork.freedesktop.org/patch/483099/?series=102964&rev=2
>>>
>>> Signed-off-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
>>> ---
>>>   drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c      | 94 
>>> +++++++++++++++++++-----
>>>   drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h |  7 ++
>>>   2 files changed, 83 insertions(+), 18 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c 
>>> b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
>>> index 25c7eda..d1e92d89 100644
>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
>>> @@ -1013,9 +1013,18 @@ static void 
>>> dpu_encoder_virt_atomic_mode_set(struct drm_encoder *drm_enc,
>>>           if (phys->intf_idx >= INTF_0 && phys->intf_idx < INTF_MAX)
>>>               phys->hw_intf = dpu_rm_get_intf(&dpu_kms->rm, 
>>> phys->intf_idx);
>>> -        if (!phys->hw_intf) {
>>> +        if (phys->wb_idx >= WB_0 && phys->wb_idx < WB_MAX)
>>> +            phys->hw_wb = dpu_rm_get_wb(&dpu_kms->rm, phys->wb_idx);
>>> +
>>> +        if (!phys->hw_intf && !phys->hw_wb) {
>>>               DPU_ERROR_ENC(dpu_enc,
>>> -                      "no intf block assigned at idx: %d\n", i);
>>> +                      "no intf or wb block assigned at idx: %d\n", i);
>>> +            return;
>>> +        }
>>> +
>>> +        if (phys->hw_intf && phys->hw_wb) {
>>> +            DPU_ERROR_ENC(dpu_enc,
>>> +                    "invalid phys both intf and wb block at idx: 
>>> %d\n", i);
>>>               return;
>>>           }
>>> @@ -1163,16 +1172,35 @@ static enum dpu_intf 
>>> dpu_encoder_get_intf(struct dpu_mdss_cfg *catalog,
>>>   {
>>>       int i = 0;
>>> -    for (i = 0; i < catalog->intf_count; i++) {
>>> -        if (catalog->intf[i].type == type
>>> -            && catalog->intf[i].controller_id == controller_id) {
>>> -            return catalog->intf[i].id;
>>> +    if (type != INTF_WB) {
>>> +        for (i = 0; i < catalog->intf_count; i++) {
>>> +            if (catalog->intf[i].type == type
>>> +                && catalog->intf[i].controller_id == controller_id) {
>>> +                return catalog->intf[i].id;
>>> +            }
>>>           }
>>>       }
>>>       return INTF_MAX;
>>>   }
>>> +static enum dpu_wb dpu_encoder_get_wb(struct dpu_mdss_cfg *catalog,
>>> +        enum dpu_intf_type type, u32 controller_id)
>>> +{
>>> +    int i = 0;
>>> +
>>> +    if (type != INTF_WB)
>>> +        goto end;
>>> +
>>> +    for (i = 0; i < catalog->wb_count; i++) {
>>> +        if (catalog->wb[i].id == controller_id)
>>> +            return catalog->wb[i].id;
>>> +    }
>>> +
>>> +end:
>>> +    return WB_MAX;
>>> +}
>>> +
>>>   static void dpu_encoder_vblank_callback(struct drm_encoder *drm_enc,
>>>           struct dpu_encoder_phys *phy_enc)
>>>   {
>>> @@ -1887,16 +1915,32 @@ void dpu_encoder_helper_phys_cleanup(struct 
>>> dpu_encoder_phys *phys_enc)
>>>       dpu_encoder_helper_reset_mixers(phys_enc);
>>> -    for (i = 0; i < dpu_enc->num_phys_encs; i++) {
>>> -        if (dpu_enc->phys_encs[i] && 
>>> phys_enc->hw_intf->ops.bind_pingpong_blk)
>>> -            phys_enc->hw_intf->ops.bind_pingpong_blk(
>>> -                    dpu_enc->phys_encs[i]->hw_intf, false,
>>> -                    dpu_enc->phys_encs[i]->hw_pp->idx);
>>> -
>>> -        /* mark INTF flush as pending */
>>> -        if (phys_enc->hw_ctl->ops.update_pending_flush_intf)
>>> - phys_enc->hw_ctl->ops.update_pending_flush_intf(phys_enc->hw_ctl,
>>> -                    dpu_enc->phys_encs[i]->hw_intf->idx);
>>> +    /*
>>> +     * TODO: move the once-only operation like CTL flush/trigger
>>> +     * into dpu_encoder_virt_disable() and all operations which need
>>> +     * to be done per phys encoder into the phys_disable() op.
>>> +     */
>>> +    if (phys_enc->hw_wb) {
>>> +        /* disable the PP block */
>>> +        if (phys_enc->hw_wb->ops.bind_pingpong_blk)
>>> +            phys_enc->hw_wb->ops.bind_pingpong_blk(phys_enc->hw_wb, 
>>> false,
>>> +                    phys_enc->hw_pp->idx);
>>> +
>>> +        /* mark WB flush as pending */
>>> +        if (phys_enc->hw_ctl->ops.update_pending_flush_wb)
>>> +            phys_enc->hw_ctl->ops.update_pending_flush_wb(ctl, 
>>> phys_enc->hw_wb->idx);
>>> +    } else {
>>> +        for (i = 0; i < dpu_enc->num_phys_encs; i++) {
>>> +            if (dpu_enc->phys_encs[i] && 
>>> phys_enc->hw_intf->ops.bind_pingpong_blk)
>>> +                phys_enc->hw_intf->ops.bind_pingpong_blk(
>>> +                        dpu_enc->phys_encs[i]->hw_intf, false,
>>> +                        dpu_enc->phys_encs[i]->hw_pp->idx);
>>> +
>>> +            /* mark INTF flush as pending */
>>> +            if (phys_enc->hw_ctl->ops.update_pending_flush_intf)
>>> + phys_enc->hw_ctl->ops.update_pending_flush_intf(phys_enc->hw_ctl,
>>> +                        dpu_enc->phys_encs[i]->hw_intf->idx);
>>> +        }
>>>       }
>>>       /* reset the merge 3D HW block */
>>> @@ -2112,6 +2156,9 @@ static int dpu_encoder_setup_display(struct 
>>> dpu_encoder_virt *dpu_enc,
>>>       case DRM_MODE_ENCODER_TMDS:
>>>           intf_type = INTF_DP;
>>>           break;
>>> +    case DRM_MODE_ENCODER_VIRTUAL:
>>> +        intf_type = INTF_WB;
>>> +        break;
>>>       }
>>>       WARN_ON(disp_info->num_of_h_tiles < 1);
>>> @@ -2149,8 +2196,19 @@ static int dpu_encoder_setup_display(struct 
>>> dpu_encoder_virt *dpu_enc,
>>>           phys_params.intf_idx = dpu_encoder_get_intf(dpu_kms->catalog,
>>>                                                       intf_type,
>>>                                                       controller_id);
>>> -        if (phys_params.intf_idx == INTF_MAX) {
>>> -            DPU_ERROR_ENC(dpu_enc, "could not get intf: type %d, id 
>>> %d\n",
>>> +
>>> +        phys_params.wb_idx = dpu_encoder_get_wb(dpu_kms->catalog,
>>> +                intf_type, controller_id);
>>> +        /*
>>> +         * For boards which have no physical displays, having no 
>>> interface
>>> +         * is fine because it can still be used with just writeback.
>>> +         * If we try without a display on a board which uses a DPU 
>>> in which
>>> +         * writeback is not supported, then this will still fail as 
>>> it will not
>>> +         * find any writeback in the catalog.
>>> +         */
>>> +        if ((phys_params.intf_idx == INTF_MAX) &&
>>> +                (phys_params.wb_idx == WB_MAX)) {
>>> +            DPU_ERROR_ENC(dpu_enc, "could not get intf or wb: type 
>>> %d, id %d\n",
>>
>> I've commented the previous iteration by the mistake, but the comment 
>> still applies to this version too. Let's repeat it, so that we have 
>> all the comments in the single version.
>>
>> I think the comment is misleading. It is a phys_params, so it must have
>> etiher intf_idx or wb_idx, but not both of them, despite the board
>> having the interfaces or WB.
>>
>> So somthing like this might be more appropriate:
>>
>> /*
>>    * The phys_params might represent either an INTF or a WB unit, but not
>>    * both of them at the same time.
>>    */
>>
>> if ((phys_params.intf_idx == INTF_MAX) && (phys_params.wb_idx == 
>> WB_MAX)) {
>>    .... // error out
>> }
>>
>> if ((phys_params.intf_idx != INTF_MAX) && (phys_params.wb_idx == 
>> WB_MAX)) {
>>     ........ // error out
>> }
> 
> I didnt understand this condition. So if there is a valid intf but not 
> valid wb intf, why is that an error.
> 

c&p error. of course:

if ((intf_idx == INTF_MAX) && (wb_idx == INTF_MAX)) {...}

if ((intf_idx != INTF_MAX) && (wb_idx != INTF_MAX)) {...}


>>
>>
>> Looks good otherwise.
>>
>>
>>>                             intf_type, controller_id);
>>>               ret = -EINVAL;
>>>           }
>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h 
>>> b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
>>> index 544a9a4..c84b8e8 100644
>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h
>>> @@ -11,6 +11,7 @@
>>>   #include "dpu_kms.h"
>>>   #include "dpu_hw_intf.h"
>>> +#include "dpu_hw_wb.h"
>>>   #include "dpu_hw_pingpong.h"
>>>   #include "dpu_hw_ctl.h"
>>>   #include "dpu_hw_top.h"
>>> @@ -165,12 +166,14 @@ enum dpu_intr_idx {
>>>    * @hw_ctl:        Hardware interface to the ctl registers
>>>    * @hw_pp:        Hardware interface to the ping pong registers
>>>    * @hw_intf:        Hardware interface to the intf registers
>>> + * @hw_wb:        Hardware interface to the wb registers
>>>    * @dpu_kms:        Pointer to the dpu_kms top level
>>>    * @cached_mode:    DRM mode cached at mode_set time, acted on in 
>>> enable
>>>    * @enabled:        Whether the encoder has enabled and running a mode
>>>    * @split_role:        Role to play in a split-panel configuration
>>>    * @intf_mode:        Interface mode
>>>    * @intf_idx:        Interface index on dpu hardware
>>> + * @wb_idx:            Writeback index on dpu hardware
>>>    * @enc_spinlock:    Virtual-Encoder-Wide Spin Lock for IRQ purposes
>>>    * @enable_state:    Enable state tracking
>>>    * @vblank_refcount:    Reference count of vblank request
>>> @@ -193,11 +196,13 @@ struct dpu_encoder_phys {
>>>       struct dpu_hw_ctl *hw_ctl;
>>>       struct dpu_hw_pingpong *hw_pp;
>>>       struct dpu_hw_intf *hw_intf;
>>> +    struct dpu_hw_wb *hw_wb;
>>>       struct dpu_kms *dpu_kms;
>>>       struct drm_display_mode cached_mode;
>>>       enum dpu_enc_split_role split_role;
>>>       enum dpu_intf_mode intf_mode;
>>>       enum dpu_intf intf_idx;
>>> +    enum dpu_wb wb_idx;
>>>       spinlock_t *enc_spinlock;
>>>       enum dpu_enc_enable_state enable_state;
>>>       atomic_t vblank_refcount;
>>> @@ -243,6 +248,7 @@ struct dpu_encoder_phys_cmd {
>>>    * @parent_ops:        Callbacks exposed by the parent to the phys_enc
>>>    * @split_role:        Role to play in a split-panel configuration
>>>    * @intf_idx:        Interface index this phys_enc will control
>>> + * @wb_idx:            Writeback index this phys_enc will control
>>>    * @enc_spinlock:    Virtual-Encoder-Wide Spin Lock for IRQ purposes
>>>    */
>>>   struct dpu_enc_phys_init_params {
>>> @@ -251,6 +257,7 @@ struct dpu_enc_phys_init_params {
>>>       const struct dpu_encoder_virt_ops *parent_ops;
>>>       enum dpu_enc_split_role split_role;
>>>       enum dpu_intf intf_idx;
>>> +    enum dpu_wb wb_idx;
>>>       spinlock_t *enc_spinlock;
>>>   };
>>
>>


-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v5 15/19] drm/msm/dpu: initialize dpu encoder and connector for writeback
  2022-04-26  0:32   ` Laurent Pinchart
  2022-04-26  0:42     ` Abhinav Kumar
@ 2022-04-26  2:11     ` Dmitry Baryshkov
  2022-04-26 14:56       ` Laurent Pinchart
  1 sibling, 1 reply; 29+ messages in thread
From: Dmitry Baryshkov @ 2022-04-26  2:11 UTC (permalink / raw)
  To: Laurent Pinchart, Abhinav Kumar
  Cc: markyacoub, liviu.dudau, dri-devel, swboyd, seanpaul,
	quic_jesszhan, quic_aravindh, freedreno

On 26/04/2022 03:32, Laurent Pinchart wrote:
> Hi Abhinav,
> 
> On Sun, Apr 24, 2022 at 05:32:06PM -0700, Abhinav Kumar wrote:
>> Initialize dpu encoder and connector for writeback if the
>> target supports it in the catalog.
>>
>> changes in v2:
>> 	- start initialing the encoder for writeback since we
>> 	have migrated to using drm_writeback_connector_init_with_encoder()
>> 	- instead of checking for WB_2 inside _dpu_kms_initialize_writeback
>> 	call it only when its WB_2
>> 	- rebase on tip of msm-next and remove usage of priv->encoders
>>
>> changes in v3:
>> 	- none
>>
>> changes in v4:
>> 	- fix copyright years order
>>
>> Signed-off-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
>> Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>> ---
>>   drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 27 +++++++++----
>>   drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c     | 61 ++++++++++++++++++++++++++++-
>>   2 files changed, 80 insertions(+), 8 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
>> index 24870eb..2d79002 100644
>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
>> @@ -2102,7 +2102,7 @@ static void dpu_encoder_early_unregister(struct drm_encoder *encoder)
>>   }
>>   
>>   static int dpu_encoder_virt_add_phys_encs(
>> -		u32 display_caps,
>> +		struct msm_display_info *disp_info,
>>   		struct dpu_encoder_virt *dpu_enc,
>>   		struct dpu_enc_phys_init_params *params)
>>   {
>> @@ -2121,7 +2121,7 @@ static int dpu_encoder_virt_add_phys_encs(
>>   		return -EINVAL;
>>   	}
>>   
>> -	if (display_caps & MSM_DISPLAY_CAP_VID_MODE) {
>> +	if (disp_info->capabilities & MSM_DISPLAY_CAP_VID_MODE) {
>>   		enc = dpu_encoder_phys_vid_init(params);
>>   
>>   		if (IS_ERR_OR_NULL(enc)) {
>> @@ -2134,7 +2134,7 @@ static int dpu_encoder_virt_add_phys_encs(
>>   		++dpu_enc->num_phys_encs;
>>   	}
>>   
>> -	if (display_caps & MSM_DISPLAY_CAP_CMD_MODE) {
>> +	if (disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) {
>>   		enc = dpu_encoder_phys_cmd_init(params);
>>   
>>   		if (IS_ERR_OR_NULL(enc)) {
>> @@ -2147,6 +2147,19 @@ static int dpu_encoder_virt_add_phys_encs(
>>   		++dpu_enc->num_phys_encs;
>>   	}
>>   
>> +	if (disp_info->intf_type == DRM_MODE_ENCODER_VIRTUAL) {
>> +		enc = dpu_encoder_phys_wb_init(params);
>> +
>> +		if (IS_ERR_OR_NULL(enc)) {
>> +			DPU_ERROR_ENC(dpu_enc, "failed to init wb enc: %ld\n",
>> +					PTR_ERR(enc));
>> +			return enc == NULL ? -EINVAL : PTR_ERR(enc);
>> +		}
>> +
>> +		dpu_enc->phys_encs[dpu_enc->num_phys_encs] = enc;
>> +		++dpu_enc->num_phys_encs;
>> +	}
>> +
>>   	if (params->split_role == ENC_ROLE_SLAVE)
>>   		dpu_enc->cur_slave = enc;
>>   	else
>> @@ -2248,9 +2261,8 @@ static int dpu_encoder_setup_display(struct dpu_encoder_virt *dpu_enc,
>>   		}
>>   
>>   		if (!ret) {
>> -			ret = dpu_encoder_virt_add_phys_encs(disp_info->capabilities,
>> -												 dpu_enc,
>> -												 &phys_params);
>> +			ret = dpu_encoder_virt_add_phys_encs(disp_info,
>> +					dpu_enc, &phys_params);
>>   			if (ret)
>>   				DPU_ERROR_ENC(dpu_enc, "failed to add phys encs\n");
>>   		}
>> @@ -2367,8 +2379,9 @@ struct drm_encoder *dpu_encoder_init(struct drm_device *dev,
>>   	if (!dpu_enc)
>>   		return ERR_PTR(-ENOMEM);
>>   
>> +
>>   	rc = drm_encoder_init(dev, &dpu_enc->base, &dpu_encoder_funcs,
>> -			drm_enc_mode, NULL);
>> +							  drm_enc_mode, NULL);
>>   	if (rc) {
>>   		devm_kfree(dev->dev, dpu_enc);
>>   		return ERR_PTR(rc);
>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
>> index c683cab..9a406e1 100644
>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
>> @@ -1,7 +1,9 @@
>>   // SPDX-License-Identifier: GPL-2.0-only
>>   /*
>> - * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
>>    * Copyright (C) 2013 Red Hat
>> + * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
>> + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
>> + *
>>    * Author: Rob Clark <robdclark@gmail.com>
>>    */
>>   
>> @@ -15,6 +17,7 @@
>>   #include <drm/drm_crtc.h>
>>   #include <drm/drm_file.h>
>>   #include <drm/drm_vblank.h>
>> +#include <drm/drm_writeback.h>
>>   
>>   #include "msm_drv.h"
>>   #include "msm_mmu.h"
>> @@ -29,6 +32,7 @@
>>   #include "dpu_kms.h"
>>   #include "dpu_plane.h"
>>   #include "dpu_vbif.h"
>> +#include "dpu_writeback.h"
>>   
>>   #define CREATE_TRACE_POINTS
>>   #include "dpu_trace.h"
>> @@ -648,6 +652,45 @@ static int _dpu_kms_initialize_displayport(struct drm_device *dev,
>>   	return 0;
>>   }
>>   
>> +static int _dpu_kms_initialize_writeback(struct drm_device *dev,
>> +		struct msm_drm_private *priv, struct dpu_kms *dpu_kms,
>> +		const u32 *wb_formats, int n_formats)
>> +{
>> +	struct drm_encoder *encoder = NULL;
>> +	struct msm_display_info info;
>> +	int rc;
>> +
>> +	encoder = dpu_encoder_init(dev, DRM_MODE_ENCODER_VIRTUAL);
> 
> I'm puzzled. I thought the whole purpose of the
> drm_writeback_connector_init_with_encoder() function was to share an
> encoder between writeback and a real display output, but the encoder you
> create here seems to be specific to writeback. What am I missing ?

The encoder instance is specific to the writeback, however the encoder's 
code is shared between the virtual and 'real' encoders. All the code for 
encoder callbacks, resource management, irq handling is shared between 
them. It wouldn't be practical to duplicate or rewrite the whole 
dpu_encoder.c. During the design stage we have discussed several other 
possibile solutions. All of them look pretty ugly.

> 
>> +	if (IS_ERR(encoder)) {
>> +		DPU_ERROR("encoder init failed for dsi display\n");
>> +		return PTR_ERR(encoder);
>> +	}
>> +
>> +	memset(&info, 0, sizeof(info));
>> +
>> +	rc = dpu_writeback_init(dev, encoder, wb_formats,
>> +			n_formats);
>> +	if (rc) {
>> +		DPU_ERROR("dpu_writeback_init, rc = %d\n", rc);
>> +		drm_encoder_cleanup(encoder);
>> +		return rc;
>> +	}
>> +
>> +	info.num_of_h_tiles = 1;
>> +	/* use only WB idx 2 instance for DPU */
>> +	info.h_tile_instance[0] = WB_2;
>> +	info.intf_type = encoder->encoder_type;
>> +
>> +	rc = dpu_encoder_setup(dev, encoder, &info);
>> +	if (rc) {
>> +		DPU_ERROR("failed to setup DPU encoder %d: rc:%d\n",
>> +				  encoder->base.id, rc);
>> +		return rc;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>>   /**
>>    * _dpu_kms_setup_displays - create encoders, bridges and connectors
>>    *                           for underlying displays
>> @@ -661,6 +704,7 @@ static int _dpu_kms_setup_displays(struct drm_device *dev,
>>   				    struct dpu_kms *dpu_kms)
>>   {
>>   	int rc = 0;
>> +	int i;
>>   
>>   	rc = _dpu_kms_initialize_dsi(dev, priv, dpu_kms);
>>   	if (rc) {
>> @@ -674,6 +718,21 @@ static int _dpu_kms_setup_displays(struct drm_device *dev,
>>   		return rc;
>>   	}
>>   
>> +	/* Since WB isn't a driver check the catalog before initializing */
>> +	if (dpu_kms->catalog->wb_count) {
>> +		for (i = 0; i < dpu_kms->catalog->wb_count; i++) {
>> +			if (dpu_kms->catalog->wb[i].id == WB_2) {
>> +				rc = _dpu_kms_initialize_writeback(dev, priv, dpu_kms,
>> +						dpu_kms->catalog->wb[i].format_list,
>> +						dpu_kms->catalog->wb[i].num_formats);
>> +				if (rc) {
>> +					DPU_ERROR("initialize_WB failed, rc = %d\n", rc);
>> +					return rc;
>> +				}
>> +			}
>> +		}
>> +	}
>> +
>>   	return rc;
>>   }
>>   
> 


-- 
With best wishes
Dmitry

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v5 15/19] drm/msm/dpu: initialize dpu encoder and connector for writeback
  2022-04-26  2:11     ` Dmitry Baryshkov
@ 2022-04-26 14:56       ` Laurent Pinchart
  2022-04-26 14:59         ` Abhinav Kumar
  0 siblings, 1 reply; 29+ messages in thread
From: Laurent Pinchart @ 2022-04-26 14:56 UTC (permalink / raw)
  To: Dmitry Baryshkov
  Cc: markyacoub, liviu.dudau, Abhinav Kumar, dri-devel, swboyd,
	seanpaul, quic_jesszhan, quic_aravindh, freedreno

On Tue, Apr 26, 2022 at 05:11:41AM +0300, Dmitry Baryshkov wrote:
> On 26/04/2022 03:32, Laurent Pinchart wrote:
> > On Sun, Apr 24, 2022 at 05:32:06PM -0700, Abhinav Kumar wrote:
> >> Initialize dpu encoder and connector for writeback if the
> >> target supports it in the catalog.
> >>
> >> changes in v2:
> >> 	- start initialing the encoder for writeback since we
> >> 	have migrated to using drm_writeback_connector_init_with_encoder()
> >> 	- instead of checking for WB_2 inside _dpu_kms_initialize_writeback
> >> 	call it only when its WB_2
> >> 	- rebase on tip of msm-next and remove usage of priv->encoders
> >>
> >> changes in v3:
> >> 	- none
> >>
> >> changes in v4:
> >> 	- fix copyright years order
> >>
> >> Signed-off-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
> >> Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> >> ---
> >>   drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 27 +++++++++----
> >>   drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c     | 61 ++++++++++++++++++++++++++++-
> >>   2 files changed, 80 insertions(+), 8 deletions(-)
> >>
> >> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> >> index 24870eb..2d79002 100644
> >> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> >> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
> >> @@ -2102,7 +2102,7 @@ static void dpu_encoder_early_unregister(struct drm_encoder *encoder)
> >>   }
> >>   
> >>   static int dpu_encoder_virt_add_phys_encs(
> >> -		u32 display_caps,
> >> +		struct msm_display_info *disp_info,
> >>   		struct dpu_encoder_virt *dpu_enc,
> >>   		struct dpu_enc_phys_init_params *params)
> >>   {
> >> @@ -2121,7 +2121,7 @@ static int dpu_encoder_virt_add_phys_encs(
> >>   		return -EINVAL;
> >>   	}
> >>   
> >> -	if (display_caps & MSM_DISPLAY_CAP_VID_MODE) {
> >> +	if (disp_info->capabilities & MSM_DISPLAY_CAP_VID_MODE) {
> >>   		enc = dpu_encoder_phys_vid_init(params);
> >>   
> >>   		if (IS_ERR_OR_NULL(enc)) {
> >> @@ -2134,7 +2134,7 @@ static int dpu_encoder_virt_add_phys_encs(
> >>   		++dpu_enc->num_phys_encs;
> >>   	}
> >>   
> >> -	if (display_caps & MSM_DISPLAY_CAP_CMD_MODE) {
> >> +	if (disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) {
> >>   		enc = dpu_encoder_phys_cmd_init(params);
> >>   
> >>   		if (IS_ERR_OR_NULL(enc)) {
> >> @@ -2147,6 +2147,19 @@ static int dpu_encoder_virt_add_phys_encs(
> >>   		++dpu_enc->num_phys_encs;
> >>   	}
> >>   
> >> +	if (disp_info->intf_type == DRM_MODE_ENCODER_VIRTUAL) {
> >> +		enc = dpu_encoder_phys_wb_init(params);
> >> +
> >> +		if (IS_ERR_OR_NULL(enc)) {
> >> +			DPU_ERROR_ENC(dpu_enc, "failed to init wb enc: %ld\n",
> >> +					PTR_ERR(enc));
> >> +			return enc == NULL ? -EINVAL : PTR_ERR(enc);
> >> +		}
> >> +
> >> +		dpu_enc->phys_encs[dpu_enc->num_phys_encs] = enc;
> >> +		++dpu_enc->num_phys_encs;
> >> +	}
> >> +
> >>   	if (params->split_role == ENC_ROLE_SLAVE)
> >>   		dpu_enc->cur_slave = enc;
> >>   	else
> >> @@ -2248,9 +2261,8 @@ static int dpu_encoder_setup_display(struct dpu_encoder_virt *dpu_enc,
> >>   		}
> >>   
> >>   		if (!ret) {
> >> -			ret = dpu_encoder_virt_add_phys_encs(disp_info->capabilities,
> >> -												 dpu_enc,
> >> -												 &phys_params);
> >> +			ret = dpu_encoder_virt_add_phys_encs(disp_info,
> >> +					dpu_enc, &phys_params);
> >>   			if (ret)
> >>   				DPU_ERROR_ENC(dpu_enc, "failed to add phys encs\n");
> >>   		}
> >> @@ -2367,8 +2379,9 @@ struct drm_encoder *dpu_encoder_init(struct drm_device *dev,
> >>   	if (!dpu_enc)
> >>   		return ERR_PTR(-ENOMEM);
> >>   
> >> +
> >>   	rc = drm_encoder_init(dev, &dpu_enc->base, &dpu_encoder_funcs,
> >> -			drm_enc_mode, NULL);
> >> +							  drm_enc_mode, NULL);
> >>   	if (rc) {
> >>   		devm_kfree(dev->dev, dpu_enc);
> >>   		return ERR_PTR(rc);
> >> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
> >> index c683cab..9a406e1 100644
> >> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
> >> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
> >> @@ -1,7 +1,9 @@
> >>   // SPDX-License-Identifier: GPL-2.0-only
> >>   /*
> >> - * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
> >>    * Copyright (C) 2013 Red Hat
> >> + * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
> >> + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
> >> + *
> >>    * Author: Rob Clark <robdclark@gmail.com>
> >>    */
> >>   
> >> @@ -15,6 +17,7 @@
> >>   #include <drm/drm_crtc.h>
> >>   #include <drm/drm_file.h>
> >>   #include <drm/drm_vblank.h>
> >> +#include <drm/drm_writeback.h>
> >>   
> >>   #include "msm_drv.h"
> >>   #include "msm_mmu.h"
> >> @@ -29,6 +32,7 @@
> >>   #include "dpu_kms.h"
> >>   #include "dpu_plane.h"
> >>   #include "dpu_vbif.h"
> >> +#include "dpu_writeback.h"
> >>   
> >>   #define CREATE_TRACE_POINTS
> >>   #include "dpu_trace.h"
> >> @@ -648,6 +652,45 @@ static int _dpu_kms_initialize_displayport(struct drm_device *dev,
> >>   	return 0;
> >>   }
> >>   
> >> +static int _dpu_kms_initialize_writeback(struct drm_device *dev,
> >> +		struct msm_drm_private *priv, struct dpu_kms *dpu_kms,
> >> +		const u32 *wb_formats, int n_formats)
> >> +{
> >> +	struct drm_encoder *encoder = NULL;
> >> +	struct msm_display_info info;
> >> +	int rc;
> >> +
> >> +	encoder = dpu_encoder_init(dev, DRM_MODE_ENCODER_VIRTUAL);
> > 
> > I'm puzzled. I thought the whole purpose of the
> > drm_writeback_connector_init_with_encoder() function was to share an
> > encoder between writeback and a real display output, but the encoder you
> > create here seems to be specific to writeback. What am I missing ?
> 
> The encoder instance is specific to the writeback, however the encoder's 
> code is shared between the virtual and 'real' encoders. All the code for 
> encoder callbacks, resource management, irq handling is shared between 
> them. It wouldn't be practical to duplicate or rewrite the whole 
> dpu_encoder.c. During the design stage we have discussed several other 
> possibile solutions. All of them look pretty ugly.

Does it mean that the output paths and the writeback paths have separate
resources ?

> >> +	if (IS_ERR(encoder)) {
> >> +		DPU_ERROR("encoder init failed for dsi display\n");
> >> +		return PTR_ERR(encoder);
> >> +	}
> >> +
> >> +	memset(&info, 0, sizeof(info));
> >> +
> >> +	rc = dpu_writeback_init(dev, encoder, wb_formats,
> >> +			n_formats);
> >> +	if (rc) {
> >> +		DPU_ERROR("dpu_writeback_init, rc = %d\n", rc);
> >> +		drm_encoder_cleanup(encoder);
> >> +		return rc;
> >> +	}
> >> +
> >> +	info.num_of_h_tiles = 1;
> >> +	/* use only WB idx 2 instance for DPU */
> >> +	info.h_tile_instance[0] = WB_2;
> >> +	info.intf_type = encoder->encoder_type;
> >> +
> >> +	rc = dpu_encoder_setup(dev, encoder, &info);
> >> +	if (rc) {
> >> +		DPU_ERROR("failed to setup DPU encoder %d: rc:%d\n",
> >> +				  encoder->base.id, rc);
> >> +		return rc;
> >> +	}
> >> +
> >> +	return 0;
> >> +}
> >> +
> >>   /**
> >>    * _dpu_kms_setup_displays - create encoders, bridges and connectors
> >>    *                           for underlying displays
> >> @@ -661,6 +704,7 @@ static int _dpu_kms_setup_displays(struct drm_device *dev,
> >>   				    struct dpu_kms *dpu_kms)
> >>   {
> >>   	int rc = 0;
> >> +	int i;
> >>   
> >>   	rc = _dpu_kms_initialize_dsi(dev, priv, dpu_kms);
> >>   	if (rc) {
> >> @@ -674,6 +718,21 @@ static int _dpu_kms_setup_displays(struct drm_device *dev,
> >>   		return rc;
> >>   	}
> >>   
> >> +	/* Since WB isn't a driver check the catalog before initializing */
> >> +	if (dpu_kms->catalog->wb_count) {
> >> +		for (i = 0; i < dpu_kms->catalog->wb_count; i++) {
> >> +			if (dpu_kms->catalog->wb[i].id == WB_2) {
> >> +				rc = _dpu_kms_initialize_writeback(dev, priv, dpu_kms,
> >> +						dpu_kms->catalog->wb[i].format_list,
> >> +						dpu_kms->catalog->wb[i].num_formats);
> >> +				if (rc) {
> >> +					DPU_ERROR("initialize_WB failed, rc = %d\n", rc);
> >> +					return rc;
> >> +				}
> >> +			}
> >> +		}
> >> +	}
> >> +
> >>   	return rc;
> >>   }
> >>   

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v5 15/19] drm/msm/dpu: initialize dpu encoder and connector for writeback
  2022-04-26 14:56       ` Laurent Pinchart
@ 2022-04-26 14:59         ` Abhinav Kumar
  0 siblings, 0 replies; 29+ messages in thread
From: Abhinav Kumar @ 2022-04-26 14:59 UTC (permalink / raw)
  To: Laurent Pinchart, Dmitry Baryshkov
  Cc: markyacoub, liviu.dudau, dri-devel, swboyd, seanpaul,
	quic_jesszhan, quic_aravindh, freedreno



On 4/26/2022 7:56 AM, Laurent Pinchart wrote:
> On Tue, Apr 26, 2022 at 05:11:41AM +0300, Dmitry Baryshkov wrote:
>> On 26/04/2022 03:32, Laurent Pinchart wrote:
>>> On Sun, Apr 24, 2022 at 05:32:06PM -0700, Abhinav Kumar wrote:
>>>> Initialize dpu encoder and connector for writeback if the
>>>> target supports it in the catalog.
>>>>
>>>> changes in v2:
>>>> 	- start initialing the encoder for writeback since we
>>>> 	have migrated to using drm_writeback_connector_init_with_encoder()
>>>> 	- instead of checking for WB_2 inside _dpu_kms_initialize_writeback
>>>> 	call it only when its WB_2
>>>> 	- rebase on tip of msm-next and remove usage of priv->encoders
>>>>
>>>> changes in v3:
>>>> 	- none
>>>>
>>>> changes in v4:
>>>> 	- fix copyright years order
>>>>
>>>> Signed-off-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
>>>> Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>>>> ---
>>>>    drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 27 +++++++++----
>>>>    drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c     | 61 ++++++++++++++++++++++++++++-
>>>>    2 files changed, 80 insertions(+), 8 deletions(-)
>>>>
>>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
>>>> index 24870eb..2d79002 100644
>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
>>>> @@ -2102,7 +2102,7 @@ static void dpu_encoder_early_unregister(struct drm_encoder *encoder)
>>>>    }
>>>>    
>>>>    static int dpu_encoder_virt_add_phys_encs(
>>>> -		u32 display_caps,
>>>> +		struct msm_display_info *disp_info,
>>>>    		struct dpu_encoder_virt *dpu_enc,
>>>>    		struct dpu_enc_phys_init_params *params)
>>>>    {
>>>> @@ -2121,7 +2121,7 @@ static int dpu_encoder_virt_add_phys_encs(
>>>>    		return -EINVAL;
>>>>    	}
>>>>    
>>>> -	if (display_caps & MSM_DISPLAY_CAP_VID_MODE) {
>>>> +	if (disp_info->capabilities & MSM_DISPLAY_CAP_VID_MODE) {
>>>>    		enc = dpu_encoder_phys_vid_init(params);
>>>>    
>>>>    		if (IS_ERR_OR_NULL(enc)) {
>>>> @@ -2134,7 +2134,7 @@ static int dpu_encoder_virt_add_phys_encs(
>>>>    		++dpu_enc->num_phys_encs;
>>>>    	}
>>>>    
>>>> -	if (display_caps & MSM_DISPLAY_CAP_CMD_MODE) {
>>>> +	if (disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) {
>>>>    		enc = dpu_encoder_phys_cmd_init(params);
>>>>    
>>>>    		if (IS_ERR_OR_NULL(enc)) {
>>>> @@ -2147,6 +2147,19 @@ static int dpu_encoder_virt_add_phys_encs(
>>>>    		++dpu_enc->num_phys_encs;
>>>>    	}
>>>>    
>>>> +	if (disp_info->intf_type == DRM_MODE_ENCODER_VIRTUAL) {
>>>> +		enc = dpu_encoder_phys_wb_init(params);
>>>> +
>>>> +		if (IS_ERR_OR_NULL(enc)) {
>>>> +			DPU_ERROR_ENC(dpu_enc, "failed to init wb enc: %ld\n",
>>>> +					PTR_ERR(enc));
>>>> +			return enc == NULL ? -EINVAL : PTR_ERR(enc);
>>>> +		}
>>>> +
>>>> +		dpu_enc->phys_encs[dpu_enc->num_phys_encs] = enc;
>>>> +		++dpu_enc->num_phys_encs;
>>>> +	}
>>>> +
>>>>    	if (params->split_role == ENC_ROLE_SLAVE)
>>>>    		dpu_enc->cur_slave = enc;
>>>>    	else
>>>> @@ -2248,9 +2261,8 @@ static int dpu_encoder_setup_display(struct dpu_encoder_virt *dpu_enc,
>>>>    		}
>>>>    
>>>>    		if (!ret) {
>>>> -			ret = dpu_encoder_virt_add_phys_encs(disp_info->capabilities,
>>>> -												 dpu_enc,
>>>> -												 &phys_params);
>>>> +			ret = dpu_encoder_virt_add_phys_encs(disp_info,
>>>> +					dpu_enc, &phys_params);
>>>>    			if (ret)
>>>>    				DPU_ERROR_ENC(dpu_enc, "failed to add phys encs\n");
>>>>    		}
>>>> @@ -2367,8 +2379,9 @@ struct drm_encoder *dpu_encoder_init(struct drm_device *dev,
>>>>    	if (!dpu_enc)
>>>>    		return ERR_PTR(-ENOMEM);
>>>>    
>>>> +
>>>>    	rc = drm_encoder_init(dev, &dpu_enc->base, &dpu_encoder_funcs,
>>>> -			drm_enc_mode, NULL);
>>>> +							  drm_enc_mode, NULL);
>>>>    	if (rc) {
>>>>    		devm_kfree(dev->dev, dpu_enc);
>>>>    		return ERR_PTR(rc);
>>>> diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
>>>> index c683cab..9a406e1 100644
>>>> --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
>>>> +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c
>>>> @@ -1,7 +1,9 @@
>>>>    // SPDX-License-Identifier: GPL-2.0-only
>>>>    /*
>>>> - * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
>>>>     * Copyright (C) 2013 Red Hat
>>>> + * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
>>>> + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
>>>> + *
>>>>     * Author: Rob Clark <robdclark@gmail.com>
>>>>     */
>>>>    
>>>> @@ -15,6 +17,7 @@
>>>>    #include <drm/drm_crtc.h>
>>>>    #include <drm/drm_file.h>
>>>>    #include <drm/drm_vblank.h>
>>>> +#include <drm/drm_writeback.h>
>>>>    
>>>>    #include "msm_drv.h"
>>>>    #include "msm_mmu.h"
>>>> @@ -29,6 +32,7 @@
>>>>    #include "dpu_kms.h"
>>>>    #include "dpu_plane.h"
>>>>    #include "dpu_vbif.h"
>>>> +#include "dpu_writeback.h"
>>>>    
>>>>    #define CREATE_TRACE_POINTS
>>>>    #include "dpu_trace.h"
>>>> @@ -648,6 +652,45 @@ static int _dpu_kms_initialize_displayport(struct drm_device *dev,
>>>>    	return 0;
>>>>    }
>>>>    
>>>> +static int _dpu_kms_initialize_writeback(struct drm_device *dev,
>>>> +		struct msm_drm_private *priv, struct dpu_kms *dpu_kms,
>>>> +		const u32 *wb_formats, int n_formats)
>>>> +{
>>>> +	struct drm_encoder *encoder = NULL;
>>>> +	struct msm_display_info info;
>>>> +	int rc;
>>>> +
>>>> +	encoder = dpu_encoder_init(dev, DRM_MODE_ENCODER_VIRTUAL);
>>>
>>> I'm puzzled. I thought the whole purpose of the
>>> drm_writeback_connector_init_with_encoder() function was to share an
>>> encoder between writeback and a real display output, but the encoder you
>>> create here seems to be specific to writeback. What am I missing ?
>>
>> The encoder instance is specific to the writeback, however the encoder's
>> code is shared between the virtual and 'real' encoders. All the code for
>> encoder callbacks, resource management, irq handling is shared between
>> them. It wouldn't be practical to duplicate or rewrite the whole
>> dpu_encoder.c. During the design stage we have discussed several other
>> possibile solutions. All of them look pretty ugly.
> 
> Does it mean that the output paths and the writeback paths have separate
> resources ?

They share pretty much all of the hardware resources such as clocks , 
interrupts and fetch bandwidth management.


> 
>>>> +	if (IS_ERR(encoder)) {
>>>> +		DPU_ERROR("encoder init failed for dsi display\n");
>>>> +		return PTR_ERR(encoder);
>>>> +	}
>>>> +
>>>> +	memset(&info, 0, sizeof(info));
>>>> +
>>>> +	rc = dpu_writeback_init(dev, encoder, wb_formats,
>>>> +			n_formats);
>>>> +	if (rc) {
>>>> +		DPU_ERROR("dpu_writeback_init, rc = %d\n", rc);
>>>> +		drm_encoder_cleanup(encoder);
>>>> +		return rc;
>>>> +	}
>>>> +
>>>> +	info.num_of_h_tiles = 1;
>>>> +	/* use only WB idx 2 instance for DPU */
>>>> +	info.h_tile_instance[0] = WB_2;
>>>> +	info.intf_type = encoder->encoder_type;
>>>> +
>>>> +	rc = dpu_encoder_setup(dev, encoder, &info);
>>>> +	if (rc) {
>>>> +		DPU_ERROR("failed to setup DPU encoder %d: rc:%d\n",
>>>> +				  encoder->base.id, rc);
>>>> +		return rc;
>>>> +	}
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>>    /**
>>>>     * _dpu_kms_setup_displays - create encoders, bridges and connectors
>>>>     *                           for underlying displays
>>>> @@ -661,6 +704,7 @@ static int _dpu_kms_setup_displays(struct drm_device *dev,
>>>>    				    struct dpu_kms *dpu_kms)
>>>>    {
>>>>    	int rc = 0;
>>>> +	int i;
>>>>    
>>>>    	rc = _dpu_kms_initialize_dsi(dev, priv, dpu_kms);
>>>>    	if (rc) {
>>>> @@ -674,6 +718,21 @@ static int _dpu_kms_setup_displays(struct drm_device *dev,
>>>>    		return rc;
>>>>    	}
>>>>    
>>>> +	/* Since WB isn't a driver check the catalog before initializing */
>>>> +	if (dpu_kms->catalog->wb_count) {
>>>> +		for (i = 0; i < dpu_kms->catalog->wb_count; i++) {
>>>> +			if (dpu_kms->catalog->wb[i].id == WB_2) {
>>>> +				rc = _dpu_kms_initialize_writeback(dev, priv, dpu_kms,
>>>> +						dpu_kms->catalog->wb[i].format_list,
>>>> +						dpu_kms->catalog->wb[i].num_formats);
>>>> +				if (rc) {
>>>> +					DPU_ERROR("initialize_WB failed, rc = %d\n", rc);
>>>> +					return rc;
>>>> +				}
>>>> +			}
>>>> +		}
>>>> +	}
>>>> +
>>>>    	return rc;
>>>>    }
>>>>    
> 

^ permalink raw reply	[flat|nested] 29+ messages in thread

end of thread, other threads:[~2022-04-26 14:59 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-04-25  0:31 [PATCH v5 00/19] Add writeback block support for DPU Abhinav Kumar
2022-04-25  0:31 ` [PATCH v5 01/19] drm: allow passing possible_crtcs to drm_writeback_connector_init() Abhinav Kumar
2022-04-25  0:31 ` [PATCH v5 02/19] drm: introduce drm_writeback_connector_init_with_encoder() API Abhinav Kumar
2022-04-25  0:31 ` [PATCH v5 03/19] drm/msm/dpu: add writeback blocks to the sm8250 DPU catalog Abhinav Kumar
2022-04-25  0:31 ` [PATCH v5 04/19] drm/msm/dpu: add reset_intf_cfg operation for dpu_hw_ctl Abhinav Kumar
2022-04-25  0:31 ` [PATCH v5 05/19] drm/msm/dpu: rename dpu_hw_pipe_cdp_cfg to dpu_hw_cdp_cfg Abhinav Kumar
2022-04-25  0:31 ` [PATCH v5 06/19] drm/msm/dpu: add dpu_hw_wb abstraction for writeback blocks Abhinav Kumar
2022-04-25  0:31 ` [PATCH v5 07/19] drm/msm/dpu: add writeback blocks to DPU RM Abhinav Kumar
2022-04-25  0:31 ` [PATCH v5 08/19] drm/msm/dpu: add changes to support writeback in hw_ctl Abhinav Kumar
2022-04-25  0:32 ` [PATCH v5 09/19] drm/msm/dpu: add an API to reset the encoder related hw blocks Abhinav Kumar
2022-04-25  0:32 ` [PATCH v5 10/19] drm/msm/dpu: make changes to dpu_encoder to support virtual encoder Abhinav Kumar
2022-04-26  0:21   ` Dmitry Baryshkov
2022-04-26  0:44     ` Abhinav Kumar
2022-04-26  0:46       ` Dmitry Baryshkov
2022-04-25  0:32 ` [PATCH v5 11/19] drm/msm/dpu: add encoder operations to prepare/cleanup wb job Abhinav Kumar
2022-04-25  0:32 ` [PATCH v5 12/19] drm/msm/dpu: move _dpu_plane_get_qos_lut to dpu_hw_util file Abhinav Kumar
2022-04-25  0:32 ` [PATCH v5 13/19] drm/msm/dpu: introduce the dpu_encoder_phys_* for writeback Abhinav Kumar
2022-04-25  0:32 ` [PATCH v5 14/19] drm/msm/dpu: add the writeback connector layer Abhinav Kumar
2022-04-26  0:20   ` Dmitry Baryshkov
2022-04-25  0:32 ` [PATCH v5 15/19] drm/msm/dpu: initialize dpu encoder and connector for writeback Abhinav Kumar
2022-04-26  0:32   ` Laurent Pinchart
2022-04-26  0:42     ` Abhinav Kumar
2022-04-26  2:11     ` Dmitry Baryshkov
2022-04-26 14:56       ` Laurent Pinchart
2022-04-26 14:59         ` Abhinav Kumar
2022-04-25  0:32 ` [PATCH v5 16/19] drm/msm/dpu: gracefully handle null fb commits " Abhinav Kumar
2022-04-25  0:32 ` [PATCH v5 17/19] drm/msm/dpu: add writeback blocks to the display snapshot Abhinav Kumar
2022-04-25  0:32 ` [PATCH v5 18/19] drm/msm/dpu: add wb_idx to existing DRM prints in dpu_encoder Abhinav Kumar
2022-04-25  0:32 ` [PATCH v5 19/19] drm/msm/dpu: add wb_idx to DRM traces " Abhinav Kumar

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.