瀏覽代碼

Merge "disp: msm: sde: add support for spr hw block configuration"

qctecmdr 5 年之前
父節點
當前提交
56d95ba3e2

+ 32 - 0
include/uapi/display/drm/msm_drm_pp.h

@@ -561,6 +561,38 @@ struct drm_msm_ltm_buffer {
 	__u32 status;
 };
 
+#define SPR_INIT_PARAM_SIZE_1 4
+#define SPR_INIT_PARAM_SIZE_2 5
+#define SPR_INIT_PARAM_SIZE_3 16
+#define SPR_INIT_PARAM_SIZE_4 24
+#define SPR_INIT_PARAM_SIZE_5 32
+
+/**
+ * struct drm_msm_spr_init_cfg - SPR initial configuration structure
+ *
+ */
+struct drm_msm_spr_init_cfg {
+	__u64 flags;
+	__u16 cfg0;
+	__u16 cfg1;
+	__u16 cfg2;
+	__u16 cfg3;
+	__u16 cfg4;
+	__u16 cfg5;
+	__u16 cfg6;
+	__u16 cfg7;
+	__u16 cfg8;
+	__u16 cfg9;
+	__u32 cfg10;
+	__u16 cfg11[SPR_INIT_PARAM_SIZE_1];
+	__u16 cfg12[SPR_INIT_PARAM_SIZE_1];
+	__u16 cfg13[SPR_INIT_PARAM_SIZE_1];
+	__u16 cfg14[SPR_INIT_PARAM_SIZE_2];
+	__u16 cfg15[SPR_INIT_PARAM_SIZE_5];
+	int cfg16[SPR_INIT_PARAM_SIZE_3];
+	int cfg17[SPR_INIT_PARAM_SIZE_4];
+};
+
 /**
  * struct drm_msm_ad4_manual_str_cfg - ad4 manual strength config set
  * by user-space client.

+ 4 - 0
msm/dsi/dsi_drm.c

@@ -650,6 +650,10 @@ int dsi_conn_set_info_blob(struct drm_connector *connector,
 		break;
 	}
 
+	if (panel->spr_info.enable)
+		sde_kms_info_add_keystr(info, "spr_pack_type",
+			msm_spr_pack_type_str[panel->spr_info.pack_type]);
+
 	if (mode_info && mode_info->roi_caps.enabled) {
 		sde_kms_info_add_keyint(info, "partial_update_num_roi",
 				mode_info->roi_caps.num_roi);

+ 25 - 0
msm/dsi/dsi_panel.c

@@ -1860,6 +1860,8 @@ error:
 static int dsi_panel_parse_misc_features(struct dsi_panel *panel)
 {
 	struct dsi_parser_utils *utils = &panel->utils;
+	const char *string;
+	int i, rc = 0;
 
 	panel->ulps_feature_enabled =
 		utils->read_bool(utils->data, "qcom,ulps-enabled");
@@ -1881,6 +1883,29 @@ static int dsi_panel_parse_misc_features(struct dsi_panel *panel)
 
 	panel->lp11_init = utils->read_bool(utils->data,
 			"qcom,mdss-dsi-lp11-init");
+
+	panel->spr_info.enable = false;
+	panel->spr_info.pack_type = MSM_DISPLAY_SPR_TYPE_MAX;
+
+	rc = utils->read_string(utils->data, "qcom,spr-pack-type", &string);
+	if (!rc) {
+		// find match for pack-type string
+		for (i = 0; i < MSM_DISPLAY_SPR_TYPE_MAX; i++) {
+			if (msm_spr_pack_type_str[i] &&
+				(!strcmp(string, msm_spr_pack_type_str[i]))) {
+				panel->spr_info.enable = true;
+				panel->spr_info.pack_type = i;
+				break;
+			}
+		}
+	}
+
+	pr_debug("%s source side spr packing, pack-type %s\n",
+		panel->spr_info.enable ? "enable" : "disable",
+		panel->spr_info.enable ?
+		msm_spr_pack_type_str[panel->spr_info.pack_type] : "none");
+
+
 	return 0;
 }
 

+ 7 - 0
msm/dsi/dsi_panel.h

@@ -155,6 +155,11 @@ struct drm_panel_esd_config {
 	u32 groups;
 };
 
+struct dsi_panel_spr_info {
+	bool enable;
+	enum msm_display_spr_pack_type pack_type;
+};
+
 struct dsi_panel {
 	const char *name;
 	const char *type;
@@ -203,6 +208,8 @@ struct dsi_panel {
 	char dce_pps_cmd[DSI_CMD_PPS_SIZE];
 	enum dsi_dms_mode dms_mode;
 
+	struct dsi_panel_spr_info spr_info;
+
 	bool sync_broadcast_en;
 
 	int panel_test_gpio;

+ 26 - 0
msm/msm_drv.h

@@ -231,6 +231,32 @@ enum msm_display_compression_type {
 #define MSM_DISPLAY_COMPRESSION_RATIO_NONE 1
 #define MSM_DISPLAY_COMPRESSION_RATIO_MAX 5
 
+/**
+ * enum msm_display_spr_pack_type - sub pixel rendering pack patterns supported
+ * @MSM_DISPLAY_SPR_TYPE_NONE:	        Bypass, no special packing
+ * @MSM_DISPLAY_SPR_TYPE_PENTILE:	pentile pack pattern
+ * @MSM_DISPLAY_SPR_TYPE_RGBW:		RGBW pack pattern
+ * @MSM_DISPLAY_SPR_TYPE_YYGM:		YYGM pack pattern
+ * @MSM_DISPLAY_SPR_TYPE_YYGW:		YYGW pack patterm
+ * @MSM_DISPLAY_SPR_TYPE_MAX:		max and invalid
+ */
+enum msm_display_spr_pack_type {
+	MSM_DISPLAY_SPR_TYPE_NONE,
+	MSM_DISPLAY_SPR_TYPE_PENTILE,
+	MSM_DISPLAY_SPR_TYPE_RGBW,
+	MSM_DISPLAY_SPR_TYPE_YYGM,
+	MSM_DISPLAY_SPR_TYPE_YYGW,
+	MSM_DISPLAY_SPR_TYPE_MAX
+};
+
+static const char *msm_spr_pack_type_str[MSM_DISPLAY_SPR_TYPE_MAX] = {
+	[MSM_DISPLAY_SPR_TYPE_NONE] = "",
+	[MSM_DISPLAY_SPR_TYPE_PENTILE] = "pentile",
+	[MSM_DISPLAY_SPR_TYPE_RGBW] = "rgbw",
+	[MSM_DISPLAY_SPR_TYPE_YYGM] = "yygm",
+	[MSM_DISPLAY_SPR_TYPE_YYGW] = "yygw"
+};
+
 /**
  * enum msm_display_caps - features/capabilities supported by displays
  * @MSM_DISPLAY_CAP_VID_MODE:           Video or "active" mode supported

+ 46 - 0
msm/sde/sde_color_processing.c

@@ -58,6 +58,8 @@ static void dspp_ltm_install_property(struct drm_crtc *crtc);
 
 static void dspp_rc_install_property(struct drm_crtc *crtc);
 
+static void dspp_spr_install_property(struct drm_crtc *crtc);
+
 static void dspp_vlut_install_property(struct drm_crtc *crtc);
 
 static void dspp_gamut_install_property(struct drm_crtc *crtc);
@@ -108,6 +110,7 @@ do { \
 	func[SDE_DSPP_SIXZONE] = dspp_sixzone_install_property; \
 	func[SDE_DSPP_AD] = dspp_ad_install_property; \
 	func[SDE_DSPP_LTM] = dspp_ltm_install_property; \
+	func[SDE_DSPP_SPR] = dspp_spr_install_property; \
 	func[SDE_DSPP_VLUT] = dspp_vlut_install_property; \
 	func[SDE_DSPP_GAMUT] = dspp_gamut_install_property; \
 	func[SDE_DSPP_GC] = dspp_gc_install_property; \
@@ -164,6 +167,7 @@ enum sde_cp_crtc_features {
 	SDE_CP_CRTC_DSPP_LTM_VLUT,
 	SDE_CP_CRTC_DSPP_SB,
 	SDE_CP_CRTC_DSPP_RC_MASK,
+	SDE_CP_CRTC_DSPP_SPR_INIT,
 	SDE_CP_CRTC_DSPP_MAX,
 	/* DSPP features end */
 
@@ -790,6 +794,22 @@ static int check_rc_pu_feature(struct sde_hw_dspp *hw_dspp,
 	return ret;
 }
 
+static int set_spr_init_feature(struct sde_hw_dspp *hw_dspp,
+				struct sde_hw_cp_cfg *hw_cfg,
+				struct sde_crtc *sde_crtc)
+{
+	int ret = 0;
+
+	if (!sde_crtc || !hw_dspp || !hw_dspp->ops.setup_spr_init_config) {
+		DRM_ERROR("invalid arguments\n");
+		ret = -EINVAL;
+	} else {
+		hw_dspp->ops.setup_spr_init_config(hw_dspp, hw_cfg);
+	}
+
+	return ret;
+}
+
 feature_wrapper check_crtc_feature_wrappers[SDE_CP_CRTC_MAX_FEATURES];
 #define setup_check_crtc_feature_wrappers(wrappers) \
 do { \
@@ -839,6 +859,7 @@ do { \
 	wrappers[SDE_CP_CRTC_DSPP_LTM_QUEUE_BUF3] = set_ltm_queue_buf_feature; \
 	wrappers[SDE_CP_CRTC_DSPP_LTM_HIST_CTL] = set_ltm_hist_crtl_feature; \
 	wrappers[SDE_CP_CRTC_DSPP_RC_MASK] = set_rc_mask_feature; \
+	wrappers[SDE_CP_CRTC_DSPP_SPR_INIT] = set_spr_init_feature; \
 } while (0)
 
 feature_wrapper set_crtc_pu_feature_wrappers[SDE_CP_CRTC_MAX_PU_FEATURES];
@@ -1499,6 +1520,7 @@ static const int dspp_feature_to_sub_blk_tbl[SDE_CP_CRTC_MAX_FEATURES] = {
 	[SDE_CP_CRTC_DSPP_LTM_QUEUE_BUF3] = SDE_DSPP_LTM,
 	[SDE_CP_CRTC_DSPP_LTM_VLUT] = SDE_DSPP_LTM,
 	[SDE_CP_CRTC_DSPP_SB] = SDE_DSPP_SB,
+	[SDE_CP_CRTC_DSPP_SPR_INIT] = SDE_DSPP_SPR,
 	[SDE_CP_CRTC_DSPP_RC_MASK] = SDE_DSPP_RC,
 	[SDE_CP_CRTC_DSPP_MAX] = SDE_DSPP_MAX,
 	[SDE_CP_CRTC_LM_GC] = SDE_DSPP_MAX,
@@ -2550,6 +2572,30 @@ static void dspp_rc_install_property(struct drm_crtc *crtc)
 	}
 }
 
+static void dspp_spr_install_property(struct drm_crtc *crtc)
+{
+	struct sde_kms *kms = NULL;
+	u32 version = 0;
+
+	kms = get_kms(crtc);
+	if (!kms) {
+		DRM_ERROR("!kms = %d\n ", !kms);
+		return;
+	}
+
+	version = kms->catalog->dspp[0].sblk->spr.version >> 16;
+	switch (version) {
+	case 1:
+		sde_cp_crtc_install_blob_property(crtc, "SDE_SPR_INIT_CFG_V1",
+				SDE_CP_CRTC_DSPP_SPR_INIT,
+				sizeof(struct drm_msm_spr_init_cfg));
+		break;
+	default:
+		DRM_ERROR("version %d not supported\n", version);
+		break;
+	}
+}
+
 static void lm_gc_install_property(struct drm_crtc *crtc)
 {
 	char feature_name[256];

+ 57 - 1
msm/sde/sde_hw_catalog.c

@@ -397,6 +397,13 @@ enum {
 	RC_PROP_MAX,
 };
 
+enum {
+	SPR_OFF,
+	SPR_LEN,
+	SPR_VERSION,
+	SPR_PROP_MAX,
+};
+
 enum {
 	MIXER_OFF,
 	MIXER_LEN,
@@ -717,6 +724,12 @@ static struct sde_prop_type rc_prop[] = {
 	{RC_MEM_TOTAL_SIZE, "qcom,sde-dspp-rc-mem-size", false, PROP_TYPE_U32},
 };
 
+static struct sde_prop_type spr_prop[] = {
+	{SPR_OFF, "qcom,sde-dspp-spr-off", false, PROP_TYPE_U32_ARRAY},
+	{SPR_LEN, "qcom,sde-dspp-spr-size", false, PROP_TYPE_U32},
+	{SPR_VERSION, "qcom,sde-dspp-spr-version", false, PROP_TYPE_U32},
+};
+
 static struct sde_prop_type ds_top_prop[] = {
 	{DS_TOP_OFF, "qcom,sde-dest-scaler-top-off", false, PROP_TYPE_U32},
 	{DS_TOP_LEN, "qcom,sde-dest-scaler-top-size", false, PROP_TYPE_U32},
@@ -2489,6 +2502,46 @@ end:
 	return rc;
 }
 
+static int _sde_dspp_spr_parse_dt(struct device_node *np,
+		struct sde_mdss_cfg *sde_cfg)
+{
+	int off_count, i;
+	struct sde_dt_props *props;
+	struct sde_dspp_cfg *dspp;
+	struct sde_dspp_sub_blks *sblk;
+
+	props = sde_get_dt_props(np, SPR_PROP_MAX, spr_prop,
+			ARRAY_SIZE(spr_prop), &off_count);
+	if (IS_ERR(props))
+		return PTR_ERR(props);
+
+	sde_cfg->spr_count = off_count;
+	if (off_count > sde_cfg->dspp_count) {
+		SDE_ERROR("limiting %d spr blocks to %d DSPP instances\n",
+				off_count, sde_cfg->dspp_count);
+		sde_cfg->spr_count = sde_cfg->dspp_count;
+	}
+
+	for (i = 0; i < sde_cfg->dspp_count; i++) {
+		dspp = &sde_cfg->dspp[i];
+		sblk = sde_cfg->dspp[i].sblk;
+
+		sblk->spr.id = SDE_DSPP_SPR;
+		if (props->exists[SPR_OFF] && i < off_count) {
+			sblk->spr.base = PROP_VALUE_ACCESS(props->values,
+					SPR_OFF, i);
+			sblk->spr.len = PROP_VALUE_ACCESS(props->values,
+					SPR_LEN, 0);
+			sblk->spr.version = PROP_VALUE_ACCESS(props->values,
+					SPR_VERSION, 0);
+			set_bit(SDE_DSPP_SPR, &dspp->features);
+		}
+	}
+
+	sde_put_dt_props(props);
+	return 0;
+}
+
 static int _sde_rc_parse_dt(struct device_node *np,
 		struct sde_mdss_cfg *sde_cfg)
 {
@@ -2669,8 +2722,11 @@ static int sde_dspp_parse_dt(struct device_node *np,
 	if (rc)
 		goto end;
 
-	rc = _sde_rc_parse_dt(np, sde_cfg);
+	rc = _sde_dspp_spr_parse_dt(np, sde_cfg);
+	if (rc)
+		goto end;
 
+	rc = _sde_rc_parse_dt(np, sde_cfg);
 end:
 	return rc;
 }

+ 2 - 0
msm/sde/sde_hw_catalog.h

@@ -765,6 +765,7 @@ struct sde_dspp_sub_blks {
 	struct sde_pp_blk hist;
 	struct sde_pp_blk ad;
 	struct sde_pp_blk ltm;
+	struct sde_pp_blk spr;
 	struct sde_pp_blk vlut;
 	struct sde_dspp_rc rc;
 };
@@ -1545,6 +1546,7 @@ struct sde_mdss_cfg {
 	u32 ad_count;
 	u32 ltm_count;
 	u32 rc_count;
+	u32 spr_count;
 
 	u32 merge_3d_count;
 	struct sde_merge_3d_cfg merge_3d[MAX_BLOCKS];

+ 19 - 0
msm/sde/sde_hw_dspp.c

@@ -274,6 +274,16 @@ static void dspp_rc(struct sde_hw_dspp *c)
 	}
 }
 
+static void dspp_spr(struct sde_hw_dspp *c)
+{
+	if (c->cap->sblk->spr.version == SDE_COLOR_PROCESS_VER(0x1, 0x0)) {
+		reg_dmav1_init_dspp_op_v4(SDE_DSPP_SPR, c->idx);
+		c->ops.setup_spr_init_config = reg_dmav1_setup_spr_init_cfgv1;
+	} else {
+		c->ops.setup_spr_init_config = NULL;
+	}
+}
+
 static void (*dspp_blocks[SDE_DSPP_MAX])(struct sde_hw_dspp *c);
 
 static void _init_dspp_ops(void)
@@ -291,6 +301,7 @@ static void _init_dspp_ops(void)
 	dspp_blocks[SDE_DSPP_AD] = dspp_ad;
 	dspp_blocks[SDE_DSPP_LTM] = dspp_ltm;
 	dspp_blocks[SDE_DSPP_RC] = dspp_rc;
+	dspp_blocks[SDE_DSPP_SPR] = dspp_spr;
 }
 
 static void _setup_dspp_ops(struct sde_hw_dspp *c, unsigned long features)
@@ -371,6 +382,14 @@ struct sde_hw_dspp *sde_hw_dspp_init(enum sde_dspp idx,
 				c->hw.blk_off + cfg->sblk->rc.base +
 				cfg->sblk->rc.len, c->hw.xin_id);
 	}
+
+	if ((cfg->sblk->spr.id == SDE_DSPP_SPR) && cfg->sblk->spr.base) {
+		snprintf(buf, ARRAY_SIZE(buf), "%s_%d", "spr", c->idx - DSPP_0);
+		sde_dbg_reg_register_dump_range(SDE_DBG_NAME, buf,
+				c->hw.blk_off + cfg->sblk->spr.base,
+				c->hw.blk_off + cfg->sblk->spr.base +
+				cfg->sblk->spr.len, c->hw.xin_id);
+	}
 	return c;
 
 blk_init_error:

+ 7 - 0
msm/sde/sde_hw_dspp.h

@@ -249,6 +249,13 @@ struct sde_hw_dspp_ops {
 	 * Return: 0 on success, non-zero otherwise.
 	 */
 	int (*setup_rc_data)(struct sde_hw_dspp *ctx, void *cfg);
+
+	/**
+	 * setup_spr_init_config - function to configure spr hw block
+	 * @ctx: Pointer to dspp context
+	 * @cfg: Pointer to configuration
+	 */
+	void (*setup_spr_init_config)(struct sde_hw_dspp *ctx, void *cfg);
 };
 
 /**

+ 2 - 0
msm/sde/sde_hw_reg_dma_v1.c

@@ -808,6 +808,8 @@ int init_v12(struct sde_hw_reg_dma *cfg)
 	v1_supported[LTM_VLUT] = GRP_LTM_HW_BLK_SELECT;
 	v1_supported[RC_DATA] = (GRP_DSPP_HW_BLK_SELECT |
 			GRP_MDSS_HW_BLK_SELECT);
+	v1_supported[SPR_INIT] = (GRP_DSPP_HW_BLK_SELECT |
+			GRP_MDSS_HW_BLK_SELECT);
 
 	return 0;
 }

+ 263 - 0
msm/sde/sde_hw_reg_dma_v1_color_proc.c

@@ -78,9 +78,12 @@
 		REG_DMA_HEADERS_BUFFER_SZ)
 #define LTM_VLUT_MEM_SIZE ((sizeof(struct drm_msm_ltm_data)) + \
 		REG_DMA_HEADERS_BUFFER_SZ)
+#define SPR_INIT_MEM_SIZE ((sizeof(struct drm_msm_spr_init_cfg)) + \
+		REG_DMA_HEADERS_BUFFER_SZ)
 
 #define REG_MASK(n) ((BIT(n)) - 1)
 #define REG_MASK_SHIFT(n, shift) ((REG_MASK(n)) << (shift))
+#define APPLY_MASK_AND_SHIFT(x, n, shift) ((x & (REG_MASK(n))) << (shift))
 #define REG_DMA_VIG_GAMUT_OP_MASK 0x300
 #define REG_DMA_VIG_IGC_OP_MASK 0x1001F
 #define DMA_DGM_0_OP_MODE_OFF 0x604
@@ -134,6 +137,7 @@ static u32 feature_map[SDE_DSPP_MAX] = {
 	/* MEMCOLOR can be mapped to any MEMC_SKIN/SKY/FOLIAGE/PROT*/
 	[SDE_DSPP_MEMCOLOR] = MEMC_SKIN,
 	[SDE_DSPP_SIXZONE] = SIX_ZONE,
+	[SDE_DSPP_SPR] = SPR_INIT,
 	[SDE_DSPP_DITHER] = REG_DMA_FEATURES_MAX,
 	[SDE_DSPP_HIST] = REG_DMA_FEATURES_MAX,
 	[SDE_DSPP_AD] = REG_DMA_FEATURES_MAX,
@@ -165,6 +169,7 @@ static u32 feature_reg_dma_sz[SDE_DSPP_MAX] = {
 	[SDE_DSPP_SIXZONE] = SIXZONE_MEM_SIZE,
 	[SDE_DSPP_MEMCOLOR] = MEMCOLOR_MEM_SIZE,
 	[SDE_DSPP_RC] = RC_MEM_SIZE,
+	[SDE_DSPP_SPR] = SPR_INIT_MEM_SIZE,
 };
 
 static u32 sspp_feature_reg_dma_sz[SDE_SSPP_MAX] = {
@@ -4430,3 +4435,261 @@ void reg_dmav2_setup_vig_gamutv61(struct sde_hw_pipe *ctx, void *cfg)
 exit:
 	kfree(data);
 }
+
+int reg_dmav1_setup_spr_cfg3_params(struct sde_hw_dspp *ctx,
+		struct drm_msm_spr_init_cfg *payload,
+		struct sde_reg_dma_setup_ops_cfg *dma_write_cfg,
+		struct sde_hw_reg_dma_ops *dma_ops)
+{
+	uint32_t reg_off, reg_cnt, base_off;
+	uint32_t reg[16];
+	int i, index, rc = 0;
+
+	if (!payload->cfg3)
+		return rc;
+
+	base_off = ctx->hw.blk_off + ctx->cap->sblk->spr.base;
+	reg_cnt = 2;
+	reg_off = base_off + 0x70;
+	reg[0] = APPLY_MASK_AND_SHIFT(payload->cfg13[0], 10, 0) |
+		APPLY_MASK_AND_SHIFT(payload->cfg13[1], 10, 10) |
+		APPLY_MASK_AND_SHIFT(payload->cfg13[2], 10, 20);
+	reg[1] = payload->cfg10 & REG_MASK(30);
+
+	REG_DMA_SETUP_OPS(*dma_write_cfg, reg_off, reg,
+			reg_cnt * sizeof(u32), REG_BLK_WRITE_SINGLE, 0, 0, 0);
+	rc = dma_ops->setup_payload(dma_write_cfg);
+	if (rc) {
+		DRM_ERROR("write spr cfg13 failed ret %d\n", rc);
+		return rc;
+	}
+
+	reg_cnt = ARRAY_SIZE(payload->cfg15) / 2;
+	reg_off = base_off + 0xA0;
+	for (i = 0; i < reg_cnt; i++) {
+		index = 2 * i;
+		reg[i] = APPLY_MASK_AND_SHIFT(payload->cfg15[index], 12, 0) |
+			APPLY_MASK_AND_SHIFT(payload->cfg15[index + 1], 12, 16);
+	}
+
+	REG_DMA_SETUP_OPS(*dma_write_cfg, reg_off, reg,
+			reg_cnt * sizeof(u32), REG_BLK_WRITE_SINGLE, 0, 0, 0);
+	rc = dma_ops->setup_payload(dma_write_cfg);
+	if (rc) {
+		DRM_ERROR("write spr cfg15 failed ret %d\n", rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+int reg_dmav1_setup_spr_cfg4_params(struct sde_hw_dspp *ctx,
+		struct drm_msm_spr_init_cfg *payload,
+		struct sde_reg_dma_setup_ops_cfg *dma_write_cfg,
+		struct sde_hw_reg_dma_ops *dma_ops)
+{
+	uint32_t reg_off, reg_cnt, base_off;
+	uint32_t reg[16];
+	int rc = 0;
+
+	if (!payload->cfg4)
+		return rc;
+
+	reg_cnt = 3;
+	base_off = ctx->hw.blk_off + ctx->cap->sblk->spr.base;
+	reg_off = base_off + 0x60;
+	reg[0] = payload->cfg9 & 0x0F;
+	reg[1] = APPLY_MASK_AND_SHIFT(payload->cfg12[3], 10, 0) |
+		APPLY_MASK_AND_SHIFT(payload->cfg12[0], 11, 16);
+	reg[2] = APPLY_MASK_AND_SHIFT(payload->cfg12[1], 11, 0) |
+		APPLY_MASK_AND_SHIFT(payload->cfg12[2], 11, 16);
+
+	REG_DMA_SETUP_OPS(*dma_write_cfg, reg_off, reg,
+			reg_cnt * sizeof(u32), REG_BLK_WRITE_SINGLE, 0, 0, 0);
+	rc = dma_ops->setup_payload(dma_write_cfg);
+	if (rc) {
+		DRM_ERROR("write spr cfg12 failed ret %d\n", rc);
+		return rc;
+	}
+
+	return rc;
+}
+
+void reg_dmav1_disable_spr(struct sde_hw_dspp *ctx, void *cfg)
+{
+	struct sde_reg_dma_setup_ops_cfg dma_write_cfg;
+	struct sde_hw_cp_cfg *hw_cfg = cfg;
+	struct sde_reg_dma_kickoff_cfg kick_off;
+	struct sde_hw_reg_dma_ops *dma_ops;
+	uint32_t reg_off, reg = 0;
+	int rc = 0;
+
+	dma_ops = sde_reg_dma_get_ops();
+	dma_ops->reset_reg_dma_buf(dspp_buf[SPR_INIT][ctx->idx]);
+
+	REG_DMA_INIT_OPS(dma_write_cfg, MDSS, SPR_INIT,
+			dspp_buf[SPR_INIT][ctx->idx]);
+	REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0);
+	rc = dma_ops->setup_payload(&dma_write_cfg);
+	if (rc) {
+		DRM_ERROR("spr write decode select failed ret %d\n", rc);
+		return;
+	}
+
+	reg_off = ctx->hw.blk_off + ctx->cap->sblk->spr.base + 0x04;
+	REG_DMA_SETUP_OPS(dma_write_cfg, reg_off, &reg,
+			sizeof(u32), REG_BLK_WRITE_SINGLE, 0, 0, 0);
+	rc = dma_ops->setup_payload(&dma_write_cfg);
+	if (rc) {
+		DRM_ERROR("write spr disable failed ret %d\n", rc);
+		return;
+	}
+
+	REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl,
+			dspp_buf[SPR_INIT][ctx->idx],
+			REG_DMA_WRITE, DMA_CTL_QUEUE0, WRITE_IMMEDIATE);
+	rc = dma_ops->kick_off(&kick_off);
+	if (rc) {
+		DRM_ERROR("failed to kick off ret %d\n", rc);
+		return;
+	}
+}
+
+void reg_dmav1_setup_spr_init_cfgv1(struct sde_hw_dspp *ctx, void *cfg)
+{
+	struct drm_msm_spr_init_cfg *payload = NULL;
+	struct sde_reg_dma_setup_ops_cfg dma_write_cfg;
+	struct sde_hw_cp_cfg *hw_cfg = cfg;
+	struct sde_reg_dma_kickoff_cfg kick_off;
+	struct sde_hw_reg_dma_ops *dma_ops;
+	uint32_t reg_off, reg_cnt, base_off;
+	uint32_t reg[16];
+	int i, index, rc = 0;
+
+	rc = reg_dma_dspp_check(ctx, cfg, SPR_INIT);
+	if (rc)
+		return;
+
+	if (!hw_cfg->payload)
+		return reg_dmav1_disable_spr(ctx, cfg);
+
+	if (hw_cfg->len != sizeof(struct drm_msm_spr_init_cfg)) {
+		DRM_ERROR("invalid payload size len %d exp %zd\n", hw_cfg->len,
+				sizeof(struct drm_msm_spr_init_cfg));
+		return;
+	}
+
+	payload = hw_cfg->payload;
+	base_off = ctx->hw.blk_off + ctx->cap->sblk->spr.base;
+	dma_ops = sde_reg_dma_get_ops();
+	dma_ops->reset_reg_dma_buf(dspp_buf[SPR_INIT][ctx->idx]);
+
+	REG_DMA_INIT_OPS(dma_write_cfg, MDSS, SPR_INIT,
+			dspp_buf[SPR_INIT][ctx->idx]);
+	REG_DMA_SETUP_OPS(dma_write_cfg, 0, NULL, 0, HW_BLK_SELECT, 0, 0, 0);
+	rc = dma_ops->setup_payload(&dma_write_cfg);
+	if (rc) {
+		DRM_ERROR("spr write decode select failed ret %d\n", rc);
+		return;
+	}
+
+	reg_cnt = 2;
+	reg_off = base_off + 0x04;
+	reg[0] = APPLY_MASK_AND_SHIFT(payload->cfg0, 1, 0) |
+		APPLY_MASK_AND_SHIFT(payload->cfg1, 1, 1) |
+		APPLY_MASK_AND_SHIFT(payload->cfg2, 1, 2) |
+		APPLY_MASK_AND_SHIFT(payload->cfg4, 1, 3) |
+		APPLY_MASK_AND_SHIFT(payload->cfg3, 1, 24);
+	reg[0] |= APPLY_MASK_AND_SHIFT(payload->cfg5, 4, 16);
+	reg[0] |= APPLY_MASK_AND_SHIFT(payload->cfg6, 3, 20);
+	reg[0] |= APPLY_MASK_AND_SHIFT(payload->cfg7, 2, 4);
+	reg[0] |= APPLY_MASK_AND_SHIFT(payload->cfg8, 2, 6);
+	reg[0] |= APPLY_MASK_AND_SHIFT(payload->cfg11[0], 2, 8);
+	reg[0] |= APPLY_MASK_AND_SHIFT(payload->cfg11[1], 2, 10);
+	reg[0] |= APPLY_MASK_AND_SHIFT(payload->cfg11[2], 2, 12);
+	reg[0] |= APPLY_MASK_AND_SHIFT(payload->cfg11[3], 1, 14);
+
+	reg[1] = 0;
+	if (hw_cfg->num_of_mixers == 2)
+		reg[1] = 1;
+	else if (hw_cfg->num_of_mixers == 4)
+		reg[1] = 3;
+
+	REG_DMA_SETUP_OPS(dma_write_cfg, reg_off, reg,
+			reg_cnt * sizeof(u32), REG_BLK_WRITE_SINGLE, 0, 0, 0);
+	rc = dma_ops->setup_payload(&dma_write_cfg);
+	if (rc) {
+		DRM_ERROR("write spr config failed ret %d\n", rc);
+		return;
+	}
+
+	reg_cnt = 1;
+	reg_off = base_off + 0x54;
+	reg[0] = 0;
+	for (i = 0; i < ARRAY_SIZE(payload->cfg14); i++)
+		reg[0] |= APPLY_MASK_AND_SHIFT(payload->cfg14[i], 5, 5 * i);
+
+	REG_DMA_SETUP_OPS(dma_write_cfg, reg_off, reg,
+			reg_cnt * sizeof(u32), REG_SINGLE_WRITE, 0, 0, 0);
+	rc = dma_ops->setup_payload(&dma_write_cfg);
+	if (rc) {
+		DRM_ERROR("write spr cfg14 failed ret %d\n", rc);
+		return;
+	}
+
+	reg_cnt = ARRAY_SIZE(payload->cfg17) / 6;
+	reg_off = base_off + 0x24;
+	for (i = 0; i < reg_cnt; i++) {
+		index = 6 * i;
+		reg[i] = APPLY_MASK_AND_SHIFT(payload->cfg17[index], 5, 0) |
+			APPLY_MASK_AND_SHIFT(payload->cfg17[index + 1], 5, 5) |
+			APPLY_MASK_AND_SHIFT(payload->cfg17[index + 2], 5, 10) |
+			APPLY_MASK_AND_SHIFT(payload->cfg17[index + 3], 5, 15) |
+			APPLY_MASK_AND_SHIFT(payload->cfg17[index + 4], 5, 20) |
+			APPLY_MASK_AND_SHIFT(payload->cfg17[index + 5], 5, 25);
+	}
+	reg[reg_cnt - 1] &= 0x3FF;
+
+	REG_DMA_SETUP_OPS(dma_write_cfg, reg_off, reg,
+			reg_cnt * sizeof(u32), REG_BLK_WRITE_SINGLE, 0, 0, 0);
+	rc = dma_ops->setup_payload(&dma_write_cfg);
+	if (rc) {
+		DRM_ERROR("write spr cfg17 failed ret %d\n", rc);
+		return;
+	}
+
+	reg_cnt = ARRAY_SIZE(payload->cfg16) / 2;
+	reg_off = base_off + 0x34;
+	for (i = 0; i < reg_cnt; i++) {
+		index = 2 * i;
+		reg[i] = APPLY_MASK_AND_SHIFT(payload->cfg16[index], 11, 0) |
+			APPLY_MASK_AND_SHIFT(payload->cfg16[index + 1], 11, 16);
+	}
+
+	REG_DMA_SETUP_OPS(dma_write_cfg, reg_off, reg, reg_cnt * sizeof(u32),
+			REG_BLK_WRITE_SINGLE, 0, 0, 0);
+	rc = dma_ops->setup_payload(&dma_write_cfg);
+	if (rc) {
+		DRM_ERROR("write spr cfg16 failed ret %d\n", rc);
+		return;
+	}
+
+	rc = reg_dmav1_setup_spr_cfg3_params(ctx, payload,
+			&dma_write_cfg, dma_ops);
+	if (rc)
+		return;
+
+	rc = reg_dmav1_setup_spr_cfg4_params(ctx, payload,
+			&dma_write_cfg, dma_ops);
+	if (rc)
+		return;
+
+	REG_DMA_SETUP_KICKOFF(kick_off, hw_cfg->ctl,
+			dspp_buf[SPR_INIT][ctx->idx],
+			REG_DMA_WRITE, DMA_CTL_QUEUE0, WRITE_IMMEDIATE);
+	rc = dma_ops->kick_off(&kick_off);
+	if (rc) {
+		DRM_ERROR("failed to kick off ret %d\n", rc);
+		return;
+	}
+}

+ 6 - 0
msm/sde/sde_hw_reg_dma_v1_color_proc.h

@@ -288,5 +288,11 @@ void reg_dmav2_setup_dspp_3d_gamutv43(struct sde_hw_dspp *ctx, void *cfg);
  */
 void reg_dmav2_setup_vig_gamutv61(struct sde_hw_pipe *ctx, void *cfg);
 
+/**
+ * reg_dmav1_setup_spr_init_cfgv1 - function to configure spr through LUTDMA
+ * @ctx: Pointer to dspp context
+ * @cfg: Pointer to configuration
+ */
+void reg_dmav1_setup_spr_init_cfgv1(struct sde_hw_dspp *ctx, void *cfg);
 
 #endif /* _SDE_HW_REG_DMA_V1_COLOR_PROC_H */

+ 2 - 0
msm/sde/sde_reg_dma.h

@@ -54,6 +54,7 @@ enum sde_reg_dma_read_sel {
  * @SIX_ZONE: six zone
  * @HSIC: Hue, saturation and contrast
  * @GC: gamma correction
+ * @SPR_INIT: Sub pixel rendering init feature
  * @LTM_INIT: LTM INIT
  * @LTM_ROI: LTM ROI
  * @LTM_VLUT: LTM VLUT
@@ -73,6 +74,7 @@ enum sde_reg_dma_features {
 	SIX_ZONE,
 	HSIC,
 	GC,
+	SPR_INIT,
 	LTM_INIT,
 	LTM_ROI,
 	LTM_VLUT,