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

Commit 4222a290 authored by Xu Yang's avatar Xu Yang Committed by Gerrit - the friendly Code Review server
Browse files

drm/msm/sde: Add support for AD4 manual strength



Add property for AD4 manual strength value and provide operation
to set AD4 manual strength level. The change also support AD4
manual mode in idle-power collapse.

Change-Id: I848321a3edcc15af435f1d990107f1270e8210d9
Signed-off-by: default avatarXu Yang <yangxu@codeaurora.org>
parent c9ab2da3
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -48,6 +48,7 @@ enum ad_property {
	AD_SUSPEND,
	AD_ASSERTIVE,
	AD_BACKLIGHT,
	AD_STRENGTH,
	AD_IPC_SUSPEND,
	AD_IPC_RESUME,
	AD_IPC_RESET,
+17 −0
Original line number Diff line number Diff line
@@ -133,6 +133,7 @@ enum {
	SDE_CP_CRTC_DSPP_AD_INPUT,
	SDE_CP_CRTC_DSPP_AD_ASSERTIVENESS,
	SDE_CP_CRTC_DSPP_AD_BACKLIGHT,
	SDE_CP_CRTC_DSPP_AD_STRENGTH,
	SDE_CP_CRTC_DSPP_MAX,
	/* DSPP features end */

@@ -803,6 +804,15 @@ static void sde_cp_crtc_setfeature(struct sde_cp_node *prop_node,
			ad_cfg.hw_cfg = &hw_cfg;
			hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
			break;
		case SDE_CP_CRTC_DSPP_AD_STRENGTH:
			if (!hw_dspp || !hw_dspp->ops.setup_ad) {
				ret = -EINVAL;
				continue;
			}
			ad_cfg.prop = AD_STRENGTH;
			ad_cfg.hw_cfg = &hw_cfg;
			hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
			break;
		default:
			ret = -EINVAL;
			break;
@@ -1359,6 +1369,9 @@ static void dspp_ad_install_property(struct drm_crtc *crtc)
		sde_cp_crtc_install_range_property(crtc,
			"SDE_DSPP_AD_V4_ASSERTIVENESS",
			SDE_CP_CRTC_DSPP_AD_ASSERTIVENESS, 0, (BIT(8) - 1), 0);
		sde_cp_crtc_install_range_property(crtc,
			"SDE_DSPP_AD_V4_STRENGTH",
			SDE_CP_CRTC_DSPP_AD_STRENGTH, 0, (BIT(10) - 1), 0);
		sde_cp_crtc_install_range_property(crtc, "SDE_DSPP_AD_V4_INPUT",
			SDE_CP_CRTC_DSPP_AD_INPUT, 0, U16_MAX, 0);
		sde_cp_crtc_install_range_property(crtc,
@@ -1502,6 +1515,7 @@ static void sde_cp_update_list(struct sde_cp_node *prop_node,
	case SDE_CP_CRTC_DSPP_AD_INPUT:
	case SDE_CP_CRTC_DSPP_AD_ASSERTIVENESS:
	case SDE_CP_CRTC_DSPP_AD_BACKLIGHT:
	case SDE_CP_CRTC_DSPP_AD_STRENGTH:
		if (dirty_list)
			list_add_tail(&prop_node->dirty_list, &crtc->ad_dirty);
		else
@@ -1550,6 +1564,9 @@ static int sde_cp_ad_validate_prop(struct sde_cp_node *prop_node,
		case SDE_CP_CRTC_DSPP_AD_BACKLIGHT:
			ad_prop = AD_BACKLIGHT;
			break;
		case SDE_CP_CRTC_DSPP_AD_STRENGTH:
			ad_prop = AD_STRENGTH;
			break;
		default:
			/* Not an AD property */
			return 0;
+119 −19
Original line number Diff line number Diff line
@@ -16,7 +16,12 @@
#include "sde_hw_lm.h"
#include "sde_ad4.h"

#define AD_STATE_READY(x) ((x) == (ad4_init | ad4_cfg | ad4_mode | ad4_input))
#define AD_STATE_READY(x) \
	(((x) & ad4_init) && \
	((x) & ad4_cfg) && \
	((x) & ad4_mode) && \
	(((x) & ad4_input) | ((x) & ad4_strength)))

#define MERGE_WIDTH_RIGHT 6
#define MERGE_WIDTH_LEFT 5
#define AD_IPC_FRAME_COUNT 2
@@ -26,6 +31,7 @@ enum ad4_ops_bitmask {
	ad4_cfg = BIT(AD_CFG),
	ad4_mode = BIT(AD_MODE),
	ad4_input = BIT(AD_INPUT),
	ad4_strength = BIT(AD_STRENGTH),
	ad4_ops_max = BIT(31),
};

@@ -37,6 +43,8 @@ enum ad4_state {
	ad4_state_ipcs,
	/* idle power collapse resume state */
	ad4_state_ipcr,
	/* manual mode state */
	ad4_state_manual,
	ad4_state_max,
};

@@ -48,6 +56,8 @@ static int ad4_params_check(struct sde_hw_dspp *dspp,

static int ad4_no_op_setup(struct sde_hw_dspp *dspp, struct sde_ad_hw_cfg *cfg);
static int ad4_setup_debug(struct sde_hw_dspp *dspp, struct sde_ad_hw_cfg *cfg);
static int ad4_setup_debug_manual(struct sde_hw_dspp *dspp,
		struct sde_ad_hw_cfg *cfg);
static int ad4_mode_setup(struct sde_hw_dspp *dspp, enum ad4_modes mode);
static int ad4_mode_setup_common(struct sde_hw_dspp *dspp,
		struct sde_ad_hw_cfg *cfg);
@@ -81,6 +91,10 @@ static int ad4_backlight_setup(struct sde_hw_dspp *dspp,
		struct sde_ad_hw_cfg *cfg);
static int ad4_backlight_setup_ipcr(struct sde_hw_dspp *dspp,
		struct sde_ad_hw_cfg *cfg);
static int ad4_strength_setup(struct sde_hw_dspp *dspp,
		struct sde_ad_hw_cfg *cfg);
static int ad4_strength_setup_idle(struct sde_hw_dspp *dspp,
		struct sde_ad_hw_cfg *cfg);

static int ad4_ipc_suspend_setup_run(struct sde_hw_dspp *dspp,
		struct sde_ad_hw_cfg *cfg);
@@ -103,6 +117,7 @@ static ad4_prop_setup prop_set_func[ad4_state_max][AD_PROPMAX] = {
	[ad4_state_idle][AD_SUSPEND] = ad4_suspend_setup,
	[ad4_state_idle][AD_ASSERTIVE] = ad4_assertive_setup,
	[ad4_state_idle][AD_BACKLIGHT] = ad4_backlight_setup,
	[ad4_state_idle][AD_STRENGTH] = ad4_strength_setup_idle,
	[ad4_state_idle][AD_IPC_SUSPEND] = ad4_no_op_setup,
	[ad4_state_idle][AD_IPC_RESUME] = ad4_no_op_setup,
	[ad4_state_idle][AD_IPC_RESET] = ad4_no_op_setup,
@@ -115,6 +130,7 @@ static ad4_prop_setup prop_set_func[ad4_state_max][AD_PROPMAX] = {
	[ad4_state_startup][AD_ASSERTIVE] = ad4_assertive_setup,
	[ad4_state_startup][AD_BACKLIGHT] = ad4_backlight_setup,
	[ad4_state_startup][AD_IPC_SUSPEND] = ad4_no_op_setup,
	[ad4_state_startup][AD_STRENGTH] = ad4_no_op_setup,
	[ad4_state_startup][AD_IPC_RESUME] = ad4_no_op_setup,
	[ad4_state_startup][AD_IPC_RESET] = ad4_ipc_reset_setup_startup,

@@ -125,6 +141,7 @@ static ad4_prop_setup prop_set_func[ad4_state_max][AD_PROPMAX] = {
	[ad4_state_run][AD_SUSPEND] = ad4_suspend_setup,
	[ad4_state_run][AD_ASSERTIVE] = ad4_assertive_setup,
	[ad4_state_run][AD_BACKLIGHT] = ad4_backlight_setup,
	[ad4_state_run][AD_STRENGTH] = ad4_no_op_setup,
	[ad4_state_run][AD_IPC_SUSPEND] = ad4_ipc_suspend_setup_run,
	[ad4_state_run][AD_IPC_RESUME] = ad4_no_op_setup,
	[ad4_state_run][AD_IPC_RESET] = ad4_setup_debug,
@@ -136,6 +153,7 @@ static ad4_prop_setup prop_set_func[ad4_state_max][AD_PROPMAX] = {
	[ad4_state_ipcs][AD_SUSPEND] = ad4_no_op_setup,
	[ad4_state_ipcs][AD_ASSERTIVE] = ad4_no_op_setup,
	[ad4_state_ipcs][AD_BACKLIGHT] = ad4_no_op_setup,
	[ad4_state_ipcs][AD_STRENGTH] = ad4_no_op_setup,
	[ad4_state_ipcs][AD_IPC_SUSPEND] = ad4_no_op_setup,
	[ad4_state_ipcs][AD_IPC_RESUME] = ad4_ipc_resume_setup_ipcs,
	[ad4_state_ipcs][AD_IPC_RESET] = ad4_no_op_setup,
@@ -147,9 +165,22 @@ static ad4_prop_setup prop_set_func[ad4_state_max][AD_PROPMAX] = {
	[ad4_state_ipcr][AD_SUSPEND] = ad4_suspend_setup,
	[ad4_state_ipcr][AD_ASSERTIVE] = ad4_assertive_setup_ipcr,
	[ad4_state_ipcr][AD_BACKLIGHT] = ad4_backlight_setup_ipcr,
	[ad4_state_ipcr][AD_STRENGTH] = ad4_no_op_setup,
	[ad4_state_ipcr][AD_IPC_SUSPEND] = ad4_ipc_suspend_setup_ipcr,
	[ad4_state_ipcr][AD_IPC_RESUME] = ad4_no_op_setup,
	[ad4_state_ipcr][AD_IPC_RESET] = ad4_ipc_reset_setup_ipcr,

	[ad4_state_manual][AD_MODE] = ad4_mode_setup_common,
	[ad4_state_manual][AD_INIT] = ad4_init_setup,
	[ad4_state_manual][AD_CFG] = ad4_cfg_setup,
	[ad4_state_manual][AD_INPUT] = ad4_no_op_setup,
	[ad4_state_manual][AD_SUSPEND] = ad4_no_op_setup,
	[ad4_state_manual][AD_ASSERTIVE] = ad4_no_op_setup,
	[ad4_state_manual][AD_BACKLIGHT] = ad4_no_op_setup,
	[ad4_state_manual][AD_STRENGTH] = ad4_strength_setup,
	[ad4_state_manual][AD_IPC_SUSPEND] = ad4_no_op_setup,
	[ad4_state_manual][AD_IPC_RESUME] = ad4_no_op_setup,
	[ad4_state_manual][AD_IPC_RESET] = ad4_setup_debug_manual,
};

struct ad4_info {
@@ -288,24 +319,34 @@ static int ad4_no_op_setup(struct sde_hw_dspp *dspp, struct sde_ad_hw_cfg *cfg)

static int ad4_setup_debug(struct sde_hw_dspp *dspp, struct sde_ad_hw_cfg *cfg)
{
	u32 strength = 0, i = 0;
	u32 strength = 0;
	struct sde_hw_mixer *hw_lm;

	hw_lm = cfg->hw_cfg->mixer_info;
	if ((cfg->hw_cfg->num_of_mixers == 2) && hw_lm->cfg.right_mixer) {
	if ((cfg->hw_cfg->num_of_mixers == 2) && hw_lm->cfg.right_mixer)
		/* this AD core is the salve core */
		for (i = DSPP_0; i < DSPP_MAX; i++) {
			if (info[i].is_master) {
				strength = info[i].last_str;
				break;
			}
		}
	} else {
		strength = SDE_REG_READ(&dspp->hw,
				dspp->cap->sblk->ad.base + 0x4c);
		return 0;

	strength = SDE_REG_READ(&dspp->hw, dspp->cap->sblk->ad.base + 0x4c);
	pr_debug("%s(): AD strength = %d\n", __func__, strength);

	return 0;
}

static int ad4_setup_debug_manual(struct sde_hw_dspp *dspp,
		struct sde_ad_hw_cfg *cfg)
{
	u32 strength = 0;
	struct sde_hw_mixer *hw_lm;

	hw_lm = cfg->hw_cfg->mixer_info;
	if ((cfg->hw_cfg->num_of_mixers == 2) && hw_lm->cfg.right_mixer)
		/* this AD core is the salve core */
		return 0;

	strength = SDE_REG_READ(&dspp->hw, dspp->cap->sblk->ad.base + 0x15c);
	pr_debug("%s(): AD strength = %d in manual mode\n", __func__, strength);

	return 0;
}

@@ -313,8 +354,8 @@ static int ad4_mode_setup(struct sde_hw_dspp *dspp, enum ad4_modes mode)
{
	u32 blk_offset;

	blk_offset = 0x04;
	if (mode == AD4_OFF) {
		blk_offset = 0x04;
		SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset,
				0x101);
		info[dspp->idx].state = ad4_state_idle;
@@ -328,11 +369,30 @@ static int ad4_mode_setup(struct sde_hw_dspp *dspp, enum ad4_modes mode)
		info[dspp->idx].last_als = 0x0;
		info[dspp->idx].cached_als = U64_MAX;
	} else {
		if (mode == AD4_MANUAL) {
			/*vc_control_0 */
			blk_offset = 0x138;
			SDE_REG_WRITE(&dspp->hw,
				dspp->cap->sblk->ad.base + blk_offset, 0);
			/* irdx_control_0 */
			blk_offset = 0x13c;
			SDE_REG_WRITE(&dspp->hw,
				dspp->cap->sblk->ad.base + blk_offset,
				info[dspp->idx].irdx_control_0);
		}
		if (info[dspp->idx].state == ad4_state_idle) {
			if (mode == AD4_MANUAL) {
				info[dspp->idx].state = ad4_state_manual;
				pr_debug("%s(): AD state move to manual\n",
					__func__);
			} else {
				info[dspp->idx].frame_count = 0;
				info[dspp->idx].state = ad4_state_startup;
			pr_debug("%s(): AD state move to startup\n", __func__);
				pr_debug("%s(): AD state move to startup\n",
					__func__);
			}
		}
		blk_offset = 0x04;
		SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset,
				0x100);
	}
@@ -830,7 +890,7 @@ static int ad4_cfg_setup(struct sde_hw_dspp *dspp, struct sde_ad_hw_cfg *cfg)

	info[dspp->idx].vc_control_0 = (ad_cfg->cfg_param_041 & (BIT(7) - 1));

	blk_offset += 160;
	blk_offset = 0x160;
	val = (ad_cfg->cfg_param_043 & (BIT(10) - 1));
	SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val);

@@ -1263,6 +1323,8 @@ void sde_read_intr_resp_ad4(struct sde_hw_dspp *dspp, u32 event,
				dspp->cap->sblk->ad.base + 0x2c);
		*resp_out = SDE_REG_READ(&dspp->hw,
				dspp->cap->sblk->ad.base + 0x48);
		pr_debug("%s(): AD4 input BL %u, output BL %u\n", __func__,
			(*resp_in), (*resp_out));
		break;
	default:
		break;
@@ -1445,3 +1507,41 @@ static int ad4_ipc_reset_setup_startup(struct sde_hw_dspp *dspp,

	return 0;
}

static int ad4_strength_setup(struct sde_hw_dspp *dspp,
		struct sde_ad_hw_cfg *cfg)
{
	u64 strength = 0, val;
	u32 blk_offset = 0x15c;

	if (cfg->hw_cfg->len != sizeof(u64) && cfg->hw_cfg->payload) {
		DRM_ERROR("invalid sz param exp %zd given %d cfg %pK\n",
			sizeof(u64), cfg->hw_cfg->len, cfg->hw_cfg->payload);
		return -EINVAL;
	}

	if (cfg->hw_cfg->payload)
		strength = *((u64 *)cfg->hw_cfg->payload);
	else
		strength = 0;

	/* set manual strength */
	info[dspp->idx].completed_ops_mask |= ad4_strength;
	val = (strength & (BIT(10) - 1));
	SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val);
	return 0;
}

static int ad4_strength_setup_idle(struct sde_hw_dspp *dspp,
		struct sde_ad_hw_cfg *cfg)
{
	int ret;

	ret = ad4_strength_setup(dspp, cfg);
	if (ret)
		return ret;

	if (AD_STATE_READY(info[dspp->idx].completed_ops_mask))
		ad4_mode_setup(dspp, info[dspp->idx].mode);
	return 0;
}