Просмотр исходного кода

disp: msm: sde: configure the dnsc_blur hw block

Add changes to configure the downscale blur hardware block based on
the conifgs set by user-mode. Program the ctl's writeback flush and
active bits when dnsc_blur is enabled. Bind the pingpong block that
feeds pixels to dnsc_blur hw block. Disable the active bits and unbind
the pp block binding during wb disable.

Change-Id: I1961ab437e344b13d0c186c1675a5bf79b84ea74
Signed-off-by: Veera Sundaram Sankaran <[email protected]>
Veera Sundaram Sankaran 3 лет назад
Родитель
Сommit
cc23729c87
5 измененных файлов с 214 добавлено и 34 удалено
  1. 8 0
      msm/sde/sde_connector.h
  2. 9 0
      msm/sde/sde_encoder.c
  3. 3 0
      msm/sde/sde_encoder_phys.h
  4. 78 6
      msm/sde/sde_encoder_phys_wb.c
  5. 116 28
      msm/sde/sde_wb.c

+ 8 - 0
msm/sde/sde_connector.h

@@ -18,6 +18,7 @@
 #define SDE_CONNECTOR_NAME_SIZE	16
 #define SDE_CONNECTOR_DHDR_MEMPOOL_MAX_SIZE	SZ_32
 #define MAX_CMD_RECEIVE_SIZE       256
+#define DNSC_BLUR_MAX_COUNT	1
 
 struct sde_connector;
 struct sde_connector_state;
@@ -678,6 +679,9 @@ struct sde_connector {
  * @old_topology_name: topology of previous atomic state. remove this in later
  *	kernel versions which provide drm_atomic_state old_state pointers
  * @cont_splash_populated: State was populated as part of cont. splash
+ * @dnsc_blur_count: Number of downscale blur blocks used
+ * @dnsc_blur_cfg: Configs for the downscale blur block
+ * @dnsc_blur_lut: LUT idx used for the Gaussian filter LUTs in downscale blur block
  */
 struct sde_connector_state {
 	struct drm_connector_state base;
@@ -694,6 +698,10 @@ struct sde_connector_state {
 	enum sde_rm_topology_name old_topology_name;
 
 	bool cont_splash_populated;
+
+	u32 dnsc_blur_count;
+	struct sde_drm_dnsc_blur_cfg dnsc_blur_cfg[DNSC_BLUR_MAX_COUNT];
+	u32 dnsc_blur_lut;
 };
 
 /**

+ 9 - 0
msm/sde/sde_encoder.c

@@ -3222,6 +3222,15 @@ void sde_encoder_helper_phys_disable(struct sde_encoder_phys *phys_enc,
 					phys_enc->hw_cdm->idx, true);
 	}
 
+	if (phys_enc->hw_dnsc_blur && phys_enc->hw_dnsc_blur->ops.bind_pingpong_blk &&
+			phys_enc->hw_pp) {
+		phys_enc->hw_dnsc_blur->ops.bind_pingpong_blk(phys_enc->hw_dnsc_blur,
+				false, phys_enc->hw_pp->idx);
+
+		if (ctl->ops.update_dnsc_blur_bitmask)
+			ctl->ops.update_dnsc_blur_bitmask(ctl, phys_enc->hw_dnsc_blur->idx, true);
+	}
+
 	if (phys_enc == sde_enc->cur_master && phys_enc->hw_pp &&
 			ctl->ops.reset_post_disable)
 		ctl->ops.reset_post_disable(ctl, &phys_enc->intf_cfg_v1,

+ 3 - 0
msm/sde/sde_encoder_phys.h

@@ -16,6 +16,7 @@
 #include "sde_hw_top.h"
 #include "sde_hw_wb.h"
 #include "sde_hw_cdm.h"
+#include "sde_hw_dnsc_blur.h"
 #include "sde_encoder.h"
 #include "sde_connector.h"
 
@@ -260,6 +261,7 @@ struct sde_encoder_irq {
  * @hw_qdss:		Hardware interface to the qdss registers
  * @cdm_cfg:		Chroma-down hardware configuration
  * @hw_pp:		Hardware interface to the ping pong registers
+ * @hw_dnsc_blur:	Hardware interface to the downscale blur registers
  * @sde_kms:		Pointer to the sde_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
@@ -316,6 +318,7 @@ struct sde_encoder_phys {
 	struct sde_hw_qdss *hw_qdss;
 	struct sde_hw_cdm_cfg cdm_cfg;
 	struct sde_hw_pingpong *hw_pp;
+	struct sde_hw_dnsc_blur *hw_dnsc_blur;
 	struct sde_kms *sde_kms;
 	struct drm_display_mode cached_mode;
 	enum sde_enc_split_role split_role;

+ 78 - 6
msm/sde/sde_encoder_phys_wb.c

@@ -15,6 +15,7 @@
 #include "sde_wb.h"
 #include "sde_vbif.h"
 #include "sde_crtc.h"
+#include "sde_hw_dnsc_blur.h"
 
 #define to_sde_encoder_phys_wb(x) \
 	container_of(x, struct sde_encoder_phys_wb, base)
@@ -509,6 +510,7 @@ static void _sde_encoder_phys_wb_setup_cwb(struct sde_encoder_phys *phys_enc,
 	struct sde_hw_ctl *hw_ctl = phys_enc->hw_ctl;
 	struct sde_crtc *crtc = to_sde_crtc(wb_enc->crtc);
 	struct sde_hw_pingpong *hw_pp = phys_enc->hw_pp;
+	struct sde_hw_dnsc_blur *hw_dnsc_blur = phys_enc->hw_dnsc_blur;
 	bool need_merge = (crtc->num_mixers > 1);
 	int i = 0;
 
@@ -538,6 +540,9 @@ static void _sde_encoder_phys_wb_setup_cwb(struct sde_encoder_phys *phys_enc,
 			intf_cfg.merge_3d[intf_cfg.merge_3d_count++] =
 				hw_pp->merge_3d->idx;
 
+		if (hw_dnsc_blur)
+			intf_cfg.dnsc_blur[intf_cfg.dnsc_blur_count++] = hw_dnsc_blur->idx;
+
 		if (hw_pp->ops.setup_3d_mode)
 			hw_pp->ops.setup_3d_mode(hw_pp, (enable && need_merge) ?
 					BLEND_3D_H_ROW_INT : 0);
@@ -573,16 +578,13 @@ static void _sde_encoder_phys_wb_setup_cwb(struct sde_encoder_phys *phys_enc,
 	}
 }
 
-/**
- * sde_encoder_phys_wb_setup_cdp - setup chroma down prefetch block
- * @phys_enc:	Pointer to physical encoder
- */
-static void sde_encoder_phys_wb_setup_cdp(struct sde_encoder_phys *phys_enc,
+static void _sde_encoder_phys_wb_setup_ctl(struct sde_encoder_phys *phys_enc,
 		const struct sde_format *format)
 {
 	struct sde_encoder_phys_wb *wb_enc;
 	struct sde_hw_wb *hw_wb;
 	struct sde_hw_cdm *hw_cdm;
+	struct sde_hw_dnsc_blur *hw_dnsc_blur;
 	struct sde_hw_ctl *ctl;
 	const int num_wb = 1;
 
@@ -599,6 +601,7 @@ static void sde_encoder_phys_wb_setup_cdp(struct sde_encoder_phys *phys_enc,
 	wb_enc = to_sde_encoder_phys_wb(phys_enc);
 	hw_wb = wb_enc->hw_wb;
 	hw_cdm = phys_enc->hw_cdm;
+	hw_dnsc_blur = phys_enc->hw_dnsc_blur;
 	ctl = phys_enc->hw_ctl;
 
 	if (test_bit(SDE_CTL_ACTIVE_CFG, &ctl->caps->features) &&
@@ -619,6 +622,11 @@ static void sde_encoder_phys_wb_setup_cdp(struct sde_encoder_phys *phys_enc,
 			intf_cfg_v1->cdm[0] = hw_cdm->idx;
 		}
 
+		if (hw_dnsc_blur) {
+			intf_cfg_v1->dnsc_blur_count = num_wb;
+			intf_cfg_v1->dnsc_blur[0] = hw_dnsc_blur->idx;
+		}
+
 		if (mode_3d && hw_pp && hw_pp->merge_3d &&
 			intf_cfg_v1->merge_3d_count < MAX_MERGE_3D_PER_CTL_V1)
 			intf_cfg_v1->merge_3d[intf_cfg_v1->merge_3d_count++] =
@@ -1015,6 +1023,7 @@ static void _sde_encoder_phys_wb_update_cwb_flush(
 	struct sde_hw_ctl *hw_ctl;
 	struct sde_hw_cdm *hw_cdm;
 	struct sde_hw_pingpong *hw_pp;
+	struct sde_hw_dnsc_blur *hw_dnsc_blur;
 	struct sde_crtc *crtc;
 	struct sde_crtc_state *crtc_state;
 	int i = 0;
@@ -1043,6 +1052,7 @@ static void _sde_encoder_phys_wb_update_cwb_flush(
 	hw_pp = phys_enc->hw_pp;
 	hw_wb = wb_enc->hw_wb;
 	hw_cdm = phys_enc->hw_cdm;
+	hw_dnsc_blur = phys_enc->hw_dnsc_blur;
 
 	/* In CWB mode, program actual source master sde_hw_ctl from crtc */
 	hw_ctl = crtc->mixers[0].hw_ctl;
@@ -1080,6 +1090,9 @@ static void _sde_encoder_phys_wb_update_cwb_flush(
 		hw_ctl->ops.update_bitmask(hw_ctl, SDE_HW_FLUSH_CDM,
 				hw_cdm->idx, 1);
 
+	if (hw_ctl->ops.update_dnsc_blur_bitmask && hw_dnsc_blur)
+		hw_ctl->ops.update_dnsc_blur_bitmask(hw_ctl, hw_dnsc_blur->idx, 1);
+
 	if (test_bit(SDE_WB_CWB_CTRL, &hw_wb->caps->features) ||
 			test_bit(SDE_WB_DCWB_CTRL, &hw_wb->caps->features)) {
 		if (test_bit(SDE_WB_CWB_DITHER_CTRL, &hw_wb->caps->features)) {
@@ -1147,6 +1160,7 @@ static void _sde_encoder_phys_wb_update_flush(struct sde_encoder_phys *phys_enc)
 	struct sde_hw_ctl *hw_ctl;
 	struct sde_hw_cdm *hw_cdm;
 	struct sde_hw_pingpong *hw_pp;
+	struct sde_hw_dnsc_blur *hw_dnsc_blur;
 	struct sde_ctl_flush_cfg pending_flush = {0,};
 
 	if (!phys_enc)
@@ -1157,6 +1171,7 @@ static void _sde_encoder_phys_wb_update_flush(struct sde_encoder_phys *phys_enc)
 	hw_cdm = phys_enc->hw_cdm;
 	hw_pp = phys_enc->hw_pp;
 	hw_ctl = phys_enc->hw_ctl;
+	hw_dnsc_blur = phys_enc->hw_dnsc_blur;
 
 	SDE_DEBUG("[wb:%d]\n", hw_wb->idx - WB_0);
 
@@ -1182,6 +1197,9 @@ static void _sde_encoder_phys_wb_update_flush(struct sde_encoder_phys *phys_enc)
 		hw_ctl->ops.update_bitmask(hw_ctl, SDE_HW_FLUSH_MERGE_3D,
 				hw_pp->merge_3d->idx, 1);
 
+	if (hw_ctl->ops.update_dnsc_blur_bitmask && hw_dnsc_blur)
+		hw_ctl->ops.update_dnsc_blur_bitmask(hw_ctl, hw_dnsc_blur->idx, 1);
+
 	if (hw_ctl->ops.get_pending_flush)
 		hw_ctl->ops.get_pending_flush(hw_ctl,
 				&pending_flush);
@@ -1191,6 +1209,43 @@ static void _sde_encoder_phys_wb_update_flush(struct sde_encoder_phys *phys_enc)
 			hw_wb->idx - WB_0);
 }
 
+static void _sde_encoder_phys_wb_setup_dnsc_blur(struct sde_encoder_phys *phys_enc)
+{
+	struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
+	struct sde_wb_device *wb_dev = wb_enc->wb_dev;
+	struct sde_kms *sde_kms = phys_enc->sde_kms;
+	struct sde_hw_dnsc_blur *hw_dnsc_blur = phys_enc->hw_dnsc_blur;
+	struct sde_hw_pingpong *hw_pp = phys_enc->hw_pp;
+	struct sde_connector *sde_conn;
+	struct sde_connector_state *sde_conn_state;
+	struct sde_drm_dnsc_blur_cfg *cfg;
+	int i;
+	bool enable;
+
+	if (!sde_kms->catalog->dnsc_blur_count || !hw_dnsc_blur || !hw_pp
+			|| !hw_dnsc_blur->ops.setup_dnsc_blur)
+		return;
+
+	sde_conn = to_sde_connector(wb_dev->connector);
+	sde_conn_state = to_sde_connector_state(wb_dev->connector->state);
+
+	/* swap between 0 & 1 lut idx on each config change for gaussian lut */
+	sde_conn_state->dnsc_blur_lut = 1 - sde_conn_state->dnsc_blur_lut;
+
+	for (i = 0; i < sde_conn_state->dnsc_blur_count; i++) {
+		cfg = &sde_conn_state->dnsc_blur_cfg[i];
+
+		enable = (cfg->flags & DNSC_BLUR_EN);
+		hw_dnsc_blur->ops.setup_dnsc_blur(hw_dnsc_blur, cfg, sde_conn_state->dnsc_blur_lut);
+
+		if (hw_dnsc_blur->ops.setup_dither)
+			hw_dnsc_blur->ops.setup_dither(hw_dnsc_blur, cfg);
+
+		if (hw_dnsc_blur->ops.bind_pingpong_blk)
+			hw_dnsc_blur->ops.bind_pingpong_blk(hw_dnsc_blur, enable, hw_pp->idx);
+	}
+}
+
 static void _sde_encoder_phys_wb_setup_prog_line(struct sde_encoder_phys *phys_enc)
 {
 	struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
@@ -1280,13 +1335,15 @@ static void sde_encoder_phys_wb_setup(
 
 	sde_encoder_phys_wb_setup_fb(phys_enc, fb, wb_roi);
 
-	sde_encoder_phys_wb_setup_cdp(phys_enc, wb_enc->wb_fmt);
+	_sde_encoder_phys_wb_setup_ctl(phys_enc, wb_enc->wb_fmt);
 
 	_sde_encoder_phys_wb_setup_cache(wb_enc, fb);
 
 	_sde_encoder_phys_wb_setup_cwb(phys_enc, true);
 
 	_sde_encoder_phys_wb_setup_prog_line(phys_enc);
+
+	_sde_encoder_phys_wb_setup_dnsc_blur(phys_enc);
 }
 
 static void sde_encoder_phys_wb_ctl_start_irq(void *arg, int irq_idx)
@@ -1495,6 +1552,7 @@ static void sde_encoder_phys_wb_mode_set(
 
 	phys_enc->hw_ctl = NULL;
 	phys_enc->hw_cdm = NULL;
+	phys_enc->hw_dnsc_blur = NULL;
 
 	/* Retrieve previously allocated HW Resources. CTL shouldn't fail */
 	sde_rm_init_hw_iter(&iter, phys_enc->parent->base.id, SDE_HW_BLK_CTL);
@@ -1526,6 +1584,20 @@ static void sde_encoder_phys_wb_mode_set(
 		phys_enc->hw_cdm = NULL;
 	}
 
+	/* Downscale Blur is optional */
+	sde_rm_init_hw_iter(&iter, phys_enc->parent->base.id, SDE_HW_BLK_DNSC_BLUR);
+	for (i = 0; i <= instance; i++) {
+		sde_rm_get_hw(rm, &iter);
+		if (i == instance)
+			phys_enc->hw_dnsc_blur =  to_sde_hw_dnsc_blur(iter.hw);
+	}
+
+	if (IS_ERR(phys_enc->hw_dnsc_blur)) {
+		SDE_ERROR("Downscale Blur required but not allocated: %ld\n",
+			PTR_ERR(phys_enc->hw_dnsc_blur));
+		phys_enc->hw_dnsc_blur = NULL;
+	}
+
 	phys_enc->kickoff_timeout_ms =
 		sde_encoder_helper_get_kickoff_timeout_ms(phys_enc->parent);
 

+ 116 - 28
msm/sde/sde_wb.c

@@ -304,44 +304,132 @@ error:
 	return ret;
 }
 
-int sde_wb_connector_set_property(struct drm_connector *connector,
-		struct drm_connector_state *state,
-		int property_index,
-		uint64_t value,
-		void *display)
+static void _sde_wb_connector_clear_dnsc_blur(struct drm_connector_state *state)
 {
-	struct sde_wb_device *wb_dev = display;
-	struct drm_framebuffer *out_fb;
-	int rc = 0;
+	struct sde_connector_state *cstate = to_sde_connector_state(state);
+	int i;
 
-	SDE_DEBUG("\n");
+	for (i = 0; i < cstate->dnsc_blur_count; i++)
+		memset(&cstate->dnsc_blur_cfg[i], 0, sizeof(struct sde_drm_dnsc_blur_cfg));
+	cstate->dnsc_blur_count = 0;
+}
+
+static int _sde_wb_connector_set_dnsc_blur(struct sde_wb_device *wb_dev,
+		struct drm_connector_state *state, void __user *usr_ptr)
+{
+	struct sde_connector_state *cstate = to_sde_connector_state(state);
+	struct sde_kms *sde_kms = sde_connector_get_kms(wb_dev->connector);
+	struct sde_drm_dnsc_blur_cfg *dnsc_blur_cfg = &cstate->dnsc_blur_cfg[0];
+	u32 copy_count;
+	int ret = 0, i;
+
+	if (!sde_kms || !sde_kms->catalog)
+		return -EINVAL;
+
+	if (!usr_ptr)
+		goto disable;
 
-	if (state && (property_index == CONNECTOR_PROP_OUT_FB)) {
-		const struct sde_format *sde_format;
+	/* copy only the first block */
+	if (copy_from_user(dnsc_blur_cfg, usr_ptr, sizeof(struct sde_drm_dnsc_blur_cfg))) {
+		SDE_ERROR("failed to copy dnsc_blur block 0 data\n");
+		ret = -EINVAL;
+		goto disable;
+	}
 
-		out_fb = sde_connector_get_out_fb(state);
-		if (!out_fb)
-			goto done;
+	if (dnsc_blur_cfg->num_blocks > sde_kms->catalog->dnsc_blur_count) {
+		SDE_ERROR("invalid number of dnsc_blur blocks:%d\n", dnsc_blur_cfg->num_blocks);
+		ret = -EINVAL;
+		goto disable;
+	}
 
-		sde_format = sde_get_sde_format_ext(out_fb->format->format,
-				out_fb->modifier);
-		if (!sde_format) {
-			SDE_ERROR("failed to get sde format\n");
-			rc = -EINVAL;
-			goto done;
+	/* no further data required */
+	if (dnsc_blur_cfg->num_blocks <= 1)
+		goto end;
+
+	dnsc_blur_cfg++;
+	usr_ptr += sizeof(struct sde_drm_dnsc_blur_cfg);
+	copy_count = dnsc_blur_cfg->num_blocks - 1;
+
+	/* copy rest of the blocks */
+	if ((dnsc_blur_cfg->flags & DNSC_BLUR_INDEPENDENT_BLK_CFG)) {
+		if (copy_from_user(dnsc_blur_cfg, usr_ptr,
+				copy_count * sizeof(struct sde_drm_dnsc_blur_cfg))) {
+			SDE_ERROR("failed to copy dnsc_blur data\n");
+			ret = -EINVAL;
+			goto disable;
 		}
 
-		if (!sde_wb_is_format_valid(wb_dev, out_fb->format->format,
-				out_fb->modifier)) {
-			SDE_ERROR("unsupported writeback format 0x%x/0x%llx\n",
-					out_fb->format->format,
-					out_fb->modifier);
-			rc = -EINVAL;
-			goto done;
+	/* duplicate rest of the blocks */
+	} else if (dnsc_blur_cfg->flags & DNSC_BLUR_MIRROR_BLK_CFG) {
+		for (i = 0; i < copy_count; i++) {
+			memcpy(dnsc_blur_cfg, &cstate->dnsc_blur_cfg[0],
+					sizeof(struct sde_drm_dnsc_blur_cfg));
+			dnsc_blur_cfg++;
 		}
 	}
 
-done:
+end:
+	cstate->dnsc_blur_count = dnsc_blur_cfg->num_blocks;
+	return 0;
+
+disable:
+	_sde_wb_connector_clear_dnsc_blur(state);
+	return ret;
+}
+
+static int _sde_wb_connector_set_out_fb(struct sde_wb_device *wb_dev,
+		struct drm_connector_state *state)
+{
+	struct drm_framebuffer *out_fb;
+	const struct sde_format *sde_format;
+	int rc = 0;
+
+	out_fb = sde_connector_get_out_fb(state);
+	if (!out_fb)
+		goto end;
+
+	sde_format = sde_get_sde_format_ext(out_fb->format->format, out_fb->modifier);
+	if (!sde_format) {
+		SDE_ERROR("failed to get sde format\n");
+		rc = -EINVAL;
+		goto end;
+	}
+
+	if (!sde_wb_is_format_valid(wb_dev, out_fb->format->format, out_fb->modifier)) {
+		SDE_ERROR("unsupported writeback format 0x%x/0x%llx\n",
+				out_fb->format->format, out_fb->modifier);
+		rc = -EINVAL;
+		goto end;
+	}
+
+end:
+	return rc;
+}
+
+int sde_wb_connector_set_property(struct drm_connector *connector,
+		struct drm_connector_state *state, int idx, uint64_t value, void *display)
+{
+	struct sde_wb_device *wb_dev = display;
+	int rc = 0;
+
+	if (!connector || !state || !wb_dev) {
+		SDE_ERROR("invalid argument(s)\n");
+		return -EINVAL;
+	}
+
+	switch (idx) {
+	case CONNECTOR_PROP_OUT_FB:
+		rc = _sde_wb_connector_set_out_fb(wb_dev, state);
+		break;
+	case CONNECTOR_PROP_DNSC_BLUR:
+		rc = _sde_wb_connector_set_dnsc_blur(wb_dev, state,
+				(void __user *)(uintptr_t)value);
+		break;
+	default:
+		/* nothing to do */
+		break;
+	}
+
 	return rc;
 }