Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b06afd1b authored by Kyle Yan's avatar Kyle Yan Committed by Gerrit - the friendly Code Review server
Browse files

Merge "drm/msm: Add support for PA vLut feature" into msm-4.8

parents d81c0e5f b67b0d10
Loading
Loading
Loading
Loading
+140 −46
Original line number Diff line number Diff line
@@ -22,7 +22,7 @@
#include "sde_hw_dspp.h"
#include "sde_hw_lm.h"

struct sde_color_process_node {
struct sde_cp_node {
	u32 property_id;
	u32 prop_flags;
	u32 feature;
@@ -39,7 +39,7 @@ struct sde_color_process_node {
struct sde_cp_prop_attach {
	struct drm_crtc *crtc;
	struct drm_property *prop;
	struct sde_color_process_node *prop_node;
	struct sde_cp_node *prop_node;
	const struct sde_pp_blk *pp_blk;
	u32 feature;
	void *ops;
@@ -62,6 +62,7 @@ enum {
	SDE_CP_CRTC_DSPP_DITHER,
	SDE_CP_CRTC_DSPP_HIST,
	SDE_CP_CRTC_DSPP_AD,
	SDE_CP_CRTC_DSPP_VLUT,
	SDE_CP_CRTC_DSPP_MAX,
	/* DSPP features end */

@@ -84,8 +85,43 @@ enum {
		(p)->val = val; \
	} while (0)

static int sde_cp_disable_crtc_blob_property(
				struct sde_color_process_node *prop_node)
static void sde_cp_get_hw_payload(struct sde_cp_node *prop_node,
				  struct sde_hw_cp_cfg *hw_cfg,
				  bool *feature_enabled)
{

	struct drm_property_blob *blob = NULL;

	memset(hw_cfg, 0, sizeof(*hw_cfg));
	*feature_enabled = false;

	blob = prop_node->blob_ptr;
	if (prop_node->prop_flags & DRM_MODE_PROP_BLOB) {
		if (blob) {
			hw_cfg->len = blob->length;
			hw_cfg->payload = blob->data;
			*feature_enabled = true;
		}
	} else if (prop_node->prop_flags & DRM_MODE_PROP_RANGE) {
		/* Check if local blob is Set */
		if (!blob) {
			hw_cfg->len = sizeof(prop_node->prop_val);
			if (prop_node->prop_val)
				hw_cfg->payload = &prop_node->prop_val;
		} else {
			hw_cfg->len = (prop_node->prop_val) ? blob->length :
					0;
			hw_cfg->payload = (prop_node->prop_val) ? blob->data
						: NULL;
		}
		if (prop_node->prop_val)
			*feature_enabled = true;
	} else {
		DRM_ERROR("property type is not supported\n");
	}
}

static int sde_cp_disable_crtc_blob_property(struct sde_cp_node *prop_node)
{
	struct drm_property_blob *blob = prop_node->blob_ptr;

@@ -96,23 +132,84 @@ static int sde_cp_disable_crtc_blob_property(
	return 0;
}

static int sde_cp_disable_crtc_property(struct drm_crtc *crtc,
				 struct drm_property *property,
				 struct sde_color_process_node *prop_node)
static int sde_cp_create_local_blob(struct drm_crtc *crtc, u32 feature, int len)
{
	int ret = -EINVAL;
	bool found = false;
	struct sde_cp_node *prop_node = NULL;
	struct drm_property_blob *blob_ptr;
	struct sde_crtc *sde_crtc = to_sde_crtc(crtc);

	list_for_each_entry(prop_node, &sde_crtc->feature_list, feature_list) {
		if (prop_node->feature == feature) {
			found = true;
			break;
		}
	}

	if (!found || prop_node->prop_flags & DRM_MODE_PROP_BLOB) {
		DRM_ERROR("local blob create failed prop found %d flags %d\n",
		       found, prop_node->prop_flags);
		return ret;
	}

	blob_ptr = drm_property_create_blob(crtc->dev, len, NULL);
	ret = (IS_ERR_OR_NULL(blob_ptr)) ? PTR_ERR(blob_ptr) : 0;
	if (!ret)
		prop_node->blob_ptr = blob_ptr;

	return ret;
}

static void sde_cp_destroy_local_blob(struct sde_cp_node *prop_node)
{
	if (!(prop_node->prop_flags & DRM_MODE_PROP_BLOB) &&
		prop_node->blob_ptr)
		drm_property_unreference_blob(prop_node->blob_ptr);
}

static int sde_cp_handle_range_property(struct sde_cp_node *prop_node,
					uint64_t val)
{
	int ret = 0;
	struct drm_property_blob *blob_ptr = prop_node->blob_ptr;

	if (property->flags & DRM_MODE_PROP_BLOB) {
		ret = sde_cp_disable_crtc_blob_property(prop_node);
	} else if (property->flags & DRM_MODE_PROP_RANGE) {
	if (!blob_ptr) {
		prop_node->prop_val = val;
		return 0;
	}

	if (!val) {
		prop_node->prop_val = 0;
		ret = 0;
		return 0;
	}

	ret = copy_from_user(blob_ptr->data, (void *)val, blob_ptr->length);
	if (ret) {
		DRM_ERROR("failed to get the property info ret %d", ret);
		ret = -EFAULT;
	} else {
		prop_node->prop_val = val;
	}

	return ret;
}

static int sde_cp_disable_crtc_property(struct drm_crtc *crtc,
					 struct drm_property *property,
					 struct sde_cp_node *prop_node)
{
	int ret = -EINVAL;

	if (property->flags & DRM_MODE_PROP_BLOB)
		ret = sde_cp_disable_crtc_blob_property(prop_node);
	else if (property->flags & DRM_MODE_PROP_RANGE)
		ret = sde_cp_handle_range_property(prop_node, 0);
	return ret;
}

static int sde_cp_enable_crtc_blob_property(struct drm_crtc *crtc,
				       struct sde_color_process_node *prop_node,
					       struct sde_cp_node *prop_node,
					       uint64_t val)
{
	struct drm_property_blob *blob = NULL;
@@ -136,17 +233,15 @@ static int sde_cp_enable_crtc_blob_property(struct drm_crtc *crtc,

static int sde_cp_enable_crtc_property(struct drm_crtc *crtc,
				       struct drm_property *property,
				       struct sde_color_process_node *prop_node,
				       struct sde_cp_node *prop_node,
				       uint64_t val)
{
	int ret = -EINVAL;

	if (property->flags & DRM_MODE_PROP_BLOB)
		ret = sde_cp_enable_crtc_blob_property(crtc, prop_node, val);
	else if (property->flags & DRM_MODE_PROP_RANGE) {
		ret = 0;
		prop_node->prop_val = val;
	}
	else if (property->flags & DRM_MODE_PROP_RANGE)
		ret = sde_cp_handle_range_property(prop_node, val);
	return ret;
}

@@ -215,7 +310,7 @@ static void sde_cp_crtc_install_immutable_property(struct drm_crtc *crtc,
						   u32 feature)
{
	struct drm_property *prop;
	struct sde_color_process_node *prop_node = NULL;
	struct sde_cp_node *prop_node = NULL;
	struct msm_drm_private *priv;
	struct sde_cp_prop_attach prop_attach;
	uint64_t val = 0;
@@ -257,7 +352,7 @@ static void sde_cp_crtc_install_range_property(struct drm_crtc *crtc,
					     uint64_t val)
{
	struct drm_property *prop;
	struct sde_color_process_node *prop_node = NULL;
	struct sde_cp_node *prop_node = NULL;
	struct msm_drm_private *priv;
	struct sde_cp_prop_attach prop_attach;

@@ -295,7 +390,7 @@ static void sde_cp_crtc_create_blob_property(struct drm_crtc *crtc, char *name,
					     u32 feature, void *ops)
{
	struct drm_property *prop;
	struct sde_color_process_node *prop_node = NULL;
	struct sde_cp_node *prop_node = NULL;
	struct msm_drm_private *priv;
	uint64_t val = 0;
	struct sde_cp_prop_attach prop_attach;
@@ -331,15 +426,14 @@ static void sde_cp_crtc_create_blob_property(struct drm_crtc *crtc, char *name,
}


static void sde_cp_crtc_setfeature(struct sde_color_process_node *prop_node,
static void sde_cp_crtc_setfeature(struct sde_cp_node *prop_node,
				   struct sde_crtc *sde_crtc)
{
	u32 num_mixers = sde_crtc->num_mixers;
	uint64_t val = 0;
	struct drm_property_blob *blob = NULL;
	struct sde_hw_cp_cfg hw_cfg;
	u32 num_mixers = sde_crtc->num_mixers;
	int i = 0;
	bool is_dspp = true;
	bool feature_enabled = false;

	if (!prop_node->dspp_feature_op && !prop_node->lm_feature_op) {
		DRM_ERROR("ops not set for dspp/lm\n");
@@ -347,21 +441,7 @@ static void sde_cp_crtc_setfeature(struct sde_color_process_node *prop_node,
	}

	is_dspp = !prop_node->lm_feature_op;
	memset(&hw_cfg, 0, sizeof(hw_cfg));
	if (prop_node->prop_flags & DRM_MODE_PROP_BLOB) {
		blob = prop_node->blob_ptr;
		if (blob) {
			hw_cfg.len = blob->length;
			hw_cfg.payload = blob->data;
		}
	} else if (prop_node->prop_flags & DRM_MODE_PROP_RANGE) {
		val = prop_node->prop_val;
		hw_cfg.len = sizeof(prop_node->prop_val);
		hw_cfg.payload = &prop_node->prop_val;
	} else {
		DRM_ERROR("property type is not supported\n");
		return;
	}
	sde_cp_get_hw_payload(prop_node, &hw_cfg, &feature_enabled);

	for (i = 0; i < num_mixers; i++) {
		if (is_dspp) {
@@ -377,7 +457,7 @@ static void sde_cp_crtc_setfeature(struct sde_color_process_node *prop_node,
		}
	}

	if (blob || val) {
	if (feature_enabled) {
		DRM_DEBUG_DRIVER("Add feature to active list %d\n",
				 prop_node->property_id);
		list_add_tail(&prop_node->active_list, &sde_crtc->active_list);
@@ -394,7 +474,7 @@ void sde_cp_crtc_apply_properties(struct drm_crtc *crtc)
{
	struct sde_crtc *sde_crtc = NULL;
	bool set_dspp_flush = false, set_lm_flush = false;
	struct sde_color_process_node *prop_node = NULL, *n = NULL;
	struct sde_cp_node *prop_node = NULL, *n = NULL;
	struct sde_hw_ctl *ctl;
	uint32_t flush_mask = 0;
	u32 num_mixers = 0, i = 0;
@@ -549,6 +629,19 @@ void sde_cp_crtc_install_properties(struct drm_crtc *crtc)
			sde_cp_crtc_install_immutable_property(crtc,
					feature_name, SDE_CP_CRTC_DSPP_AD);
			break;
		case SDE_DSPP_VLUT:
			snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
				"SDE_DSPP_VLUT_V",
				(hw_dspp->cap->sblk->vlut.version >> 16));
			sde_cp_crtc_install_range_property(crtc, feature_name,
				&hw_dspp->cap->sblk->vlut,
				SDE_CP_CRTC_DSPP_VLUT, hw_dspp->ops.setup_vlut,
				0, U64_MAX, 0);
			/* TODO: if blob creation fails destroy the property */
			sde_cp_create_local_blob(crtc,
					SDE_CP_CRTC_DSPP_VLUT,
				sizeof(struct drm_msm_pa_vlut));
			break;
		default:
			break;
		}
@@ -585,7 +678,7 @@ int sde_cp_crtc_set_property(struct drm_crtc *crtc,
				struct drm_property *property,
				uint64_t val)
{
	struct sde_color_process_node *prop_node = NULL;
	struct sde_cp_node *prop_node = NULL;
	struct sde_crtc *sde_crtc = NULL;
	int ret = 0;
	u8 found = 0;
@@ -632,7 +725,7 @@ int sde_cp_crtc_set_property(struct drm_crtc *crtc,
int sde_cp_crtc_get_property(struct drm_crtc *crtc,
			     struct drm_property *property, uint64_t *val)
{
	struct sde_color_process_node *prop_node = NULL;
	struct sde_cp_node *prop_node = NULL;
	struct sde_crtc *sde_crtc = NULL;
	int ret = -EINVAL;

@@ -661,7 +754,7 @@ int sde_cp_crtc_get_property(struct drm_crtc *crtc,
void sde_cp_crtc_destroy_properties(struct drm_crtc *crtc)
{
	struct sde_crtc *sde_crtc = NULL;
	struct sde_color_process_node *prop_node = NULL, *n = NULL;
	struct sde_cp_node *prop_node = NULL, *n = NULL;

	if (!crtc) {
		DRM_ERROR("invalid crtc %pK\n", crtc);
@@ -683,6 +776,7 @@ void sde_cp_crtc_destroy_properties(struct drm_crtc *crtc)
		list_del_init(&prop_node->active_list);
		list_del_init(&prop_node->dirty_list);
		list_del_init(&prop_node->feature_list);
		sde_cp_destroy_local_blob(prop_node);
		kfree(prop_node);
	}

@@ -694,7 +788,7 @@ void sde_cp_crtc_destroy_properties(struct drm_crtc *crtc)
void sde_cp_crtc_suspend(struct drm_crtc *crtc)
{
	struct sde_crtc *sde_crtc = NULL;
	struct sde_color_process_node *prop_node = NULL, *n = NULL;
	struct sde_cp_node *prop_node = NULL, *n = NULL;

	if (!crtc) {
		DRM_ERROR("crtc %pK\n", crtc);
+5 −1
Original line number Diff line number Diff line
@@ -127,7 +127,9 @@ enum {
 * @SDE_DSPP_SIXZONE         Six zone block
 * @SDE_DSPP_GAMUT           Gamut bloc
 * @SDE_DSPP_DITHER          Dither block
 * @SDE_DSPP_HIST            Histogram bloc
 * @SDE_DSPP_HIST            Histogram block
 * @SDE_DSPP_VLUT            PA VLUT block
 * @SDE_DSPP_AD              AD block
 * @SDE_DSPP_MAX             maximum value
 */
enum {
@@ -140,6 +142,7 @@ enum {
	SDE_DSPP_GAMUT,
	SDE_DSPP_DITHER,
	SDE_DSPP_HIST,
	SDE_DSPP_VLUT,
	SDE_DSPP_AD,
	SDE_DSPP_MAX
};
@@ -358,6 +361,7 @@ struct sde_dspp_sub_blks {
	struct sde_pp_blk dither;
	struct sde_pp_blk hist;
	struct sde_pp_blk ad;
	struct sde_pp_blk vlut;
};

struct sde_pingpong_sub_blks {
+3 −1
Original line number Diff line number Diff line
@@ -41,7 +41,7 @@
	(BIT(SDE_DSPP_IGC) | BIT(SDE_DSPP_PCC) |\
	BIT(SDE_DSPP_GC) | BIT(SDE_DSPP_HSIC) | BIT(SDE_DSPP_GAMUT) |\
	BIT(SDE_DSPP_DITHER) | BIT(SDE_DSPP_HIST) | BIT(SDE_DSPP_MEMCOLOR) |\
	BIT(SDE_DSPP_SIXZONE) | BIT(SDE_DSPP_AD))
	BIT(SDE_DSPP_SIXZONE) | BIT(SDE_DSPP_AD) | BIT(SDE_DSPP_VLUT))

#define PINGPONG_17X_MASK \
	(BIT(SDE_PINGPONG_TE) | BIT(SDE_PINGPONG_DSC))
@@ -362,6 +362,8 @@ static inline int set_cfg_1xx_init(struct sde_mdss_cfg *cfg)
			.version = SDE_COLOR_PROCESS_VER(0x1, 0x0)},
		.ad = {.id = SDE_DSPP_AD, .base = 0x00, .len = 0x0,
			.version = SDE_COLOR_PROCESS_VER(0x3, 0x0)},
		.vlut = {.id = SDE_DSPP_VLUT, .base = 0x1400, .len = 0x0,
			.version = SDE_COLOR_PROCESS_VER(0x1, 0x0)},
	};

	/* PINGPONG capability */
+70 −0
Original line number Diff line number Diff line
@@ -28,6 +28,28 @@
#define PCC_CONST_COEFF_MASK 0xFFFF
#define PCC_COEFF_MASK 0x3FFFF

#define REG_MASK(n) ((BIT(n)) - 1)
#define PA_SZ_VAL_MASK   BIT(31)
#define PA_SZ_SAT_MASK   BIT(30)
#define PA_SZ_HUE_MASK   BIT(29)
#define PA_CONT_MASK     BIT(28)
#define PA_VAL_MASK      BIT(27)
#define PA_SAT_MASK      BIT(26)
#define PA_HUE_MASK      BIT(25)
#define PA_LUTV_MASK     BIT(19)
#define PA_HIST_MASK     BIT(16)
#define PA_MEM_SKY_MASK  BIT(7)
#define PA_MEM_FOL_MASK  BIT(6)
#define PA_MEM_SKIN_MASK BIT(5)
#define PA_ENABLE        BIT(20)

#define PA_ENABLE_MASK (PA_SZ_VAL_MASK | PA_SZ_SAT_MASK | PA_SZ_HUE_MASK \
			| PA_CONT_MASK | PA_VAL_MASK | PA_SAT_MASK \
			| PA_HUE_MASK | PA_LUTV_MASK | PA_HIST_MASK \
			| PA_MEM_SKY_MASK | PA_MEM_FOL_MASK | PA_MEM_SKIN_MASK)

#define PA_LUT_SWAP_OFF 0x234

static struct sde_dspp_cfg *_dspp_offset(enum sde_dspp dspp,
		struct sde_mdss_cfg *m,
		void __iomem *addr,
@@ -68,6 +90,49 @@ void sde_dspp_setup_hue(struct sde_hw_dspp *dspp, void *cfg)
{
}

void sde_dspp_setup_vlut(struct sde_hw_dspp *ctx, void *cfg)
{
	struct drm_msm_pa_vlut *payload = NULL;
	struct sde_hw_cp_cfg *hw_cfg = cfg;
	u32 op_mode, tmp;
	int i = 0, j = 0;

	if (!hw_cfg  || (hw_cfg->payload && hw_cfg->len !=
			sizeof(struct drm_msm_pa_vlut))) {
		DRM_ERROR("hw %pK payload %pK payloadsize %d exp size %zd\n",
			  hw_cfg, ((hw_cfg) ? hw_cfg->payload : NULL),
			  ((hw_cfg) ? hw_cfg->len : 0),
			  sizeof(struct drm_msm_pa_vlut));
		return;
	}
	op_mode = SDE_REG_READ(&ctx->hw, 0);
	if (!hw_cfg->payload) {
		DRM_DEBUG_DRIVER("Disable vlut feature\n");
		/**
		 * In the PA_VLUT disable case, remove PA_VLUT enable bit(19)
		 * first, then check whether any other PA sub-features are
		 * enabled or not. If none of the sub-features are enabled,
		 * remove the PA global enable bit(20).
		 */
		op_mode &= ~((u32)PA_LUTV_MASK);
		if (!(op_mode & PA_ENABLE_MASK))
			op_mode &= ~((u32)PA_ENABLE);
		SDE_REG_WRITE(&ctx->hw, 0, op_mode);
		return;
	}
	payload = hw_cfg->payload;
	DRM_DEBUG_DRIVER("Enable vlut feature flags %llx\n", payload->flags);
	for (i = 0, j = 0; i < ARRAY_SIZE(payload->val); i += 2, j += 4) {
		tmp = (payload->val[i] & REG_MASK(10)) |
			((payload->val[i + 1] & REG_MASK(10)) << 16);
		SDE_REG_WRITE(&ctx->hw, (ctx->cap->sblk->vlut.base + j),
			     tmp);
	}
	SDE_REG_WRITE(&ctx->hw, PA_LUT_SWAP_OFF, 1);
	op_mode |= PA_ENABLE | PA_LUTV_MASK;
	SDE_REG_WRITE(&ctx->hw, 0, op_mode);
}

void sde_dspp_setup_pcc(struct sde_hw_dspp *ctx, void *cfg)
{
	struct sde_hw_cp_cfg *hw_cfg = cfg;
@@ -194,6 +259,11 @@ static void _setup_dspp_ops(struct sde_hw_dspp *c, unsigned long features)
				(SDE_COLOR_PROCESS_VER(0x1, 0x0)))
				c->ops.setup_hue = sde_dspp_setup_hue;
			break;
		case SDE_DSPP_VLUT:
			if (c->cap->sblk->vlut.version ==
				(SDE_COLOR_PROCESS_VER(0x1, 0x0))) {
				c->ops.setup_vlut = sde_dspp_setup_vlut;
			}
		default:
			break;
		}
+7 −0
Original line number Diff line number Diff line
@@ -118,6 +118,13 @@ struct sde_hw_dspp_ops {
	 * @cfg: Pointer to configuration
	 */
	void (*setup_cont)(struct sde_hw_dspp *ctx, void *cfg);

	/**
	 * setup_vlut - setup dspp PA VLUT
	 * @ctx: Pointer to dspp context
	 * @cfg: Pointer to configuration
	 */
	void (*setup_vlut)(struct sde_hw_dspp *ctx, void *cfg);
};

/**
Loading