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

Commit f9245d60 authored by Dhaval Patel's avatar Dhaval Patel
Browse files

drm/msm/sde: update misr support for crtc and encoder



Update misr support for crtc and encoder to allow
client to capture the misr on both software blocks.
Encoder will be able to capture misr only for video
mode interface. The patch also fixes the issues related
to misr debugfs file handling.

Format:
echo "enable/disable frame_count" > /sys/kernel/debug/
dri/0/crtc*/misr_data

Examples:
echo "1 14" > /sys/kernel/debug/dri/0/crtc*/misr_data
cat /sys/kernel/debug/dri/0/crtc*/misr_data

echo "1 0" > /sys/kernel/debug/dri/0/enc*/misr_data
cat /sys/kernel/debug/dri/0/enc*/misr_data

Change-Id: I74b23cd388e3c6e9e92bd3d97dfd76acc9246567
Signed-off-by: default avatarDhaval Patel <pdhaval@codeaurora.org>
parent 436b4a5f
Loading
Loading
Loading
Loading
+144 −14
Original line number Diff line number Diff line
@@ -51,6 +51,8 @@
#define LEFT_MIXER 0
#define RIGHT_MIXER 1

#define MISR_BUFF_SIZE			256

static inline struct sde_kms *_sde_crtc_get_kms(struct drm_crtc *crtc)
{
	struct msm_drm_private *priv;
@@ -68,6 +70,35 @@ static inline struct sde_kms *_sde_crtc_get_kms(struct drm_crtc *crtc)
	return to_sde_kms(priv->kms);
}

static inline int _sde_crtc_power_enable(struct sde_crtc *sde_crtc, bool enable)
{
	struct drm_crtc *crtc;
	struct msm_drm_private *priv;
	struct sde_kms *sde_kms;

	if (!sde_crtc) {
		SDE_ERROR("invalid sde crtc\n");
		return -EINVAL;
	}

	crtc = &sde_crtc->base;
	if (!crtc->dev || !crtc->dev->dev_private) {
		SDE_ERROR("invalid drm device\n");
		return -EINVAL;
	}

	priv = crtc->dev->dev_private;
	if (!priv->kms) {
		SDE_ERROR("invalid kms\n");
		return -EINVAL;
	}

	sde_kms = to_sde_kms(priv->kms);

	return sde_power_resource_enable(&priv->phandle, sde_kms->core_client,
									enable);
}

static void _sde_crtc_deinit_events(struct sde_crtc *sde_crtc)
{
	if (!sde_crtc)
@@ -1086,8 +1117,6 @@ static void _sde_crtc_vblank_enable_nolock(
	struct drm_device *dev;
	struct drm_crtc *crtc;
	struct drm_encoder *enc;
	struct msm_drm_private *priv;
	struct sde_kms *sde_kms;

	if (!sde_crtc) {
		SDE_ERROR("invalid crtc\n");
@@ -1096,17 +1125,11 @@ static void _sde_crtc_vblank_enable_nolock(

	crtc = &sde_crtc->base;
	dev = crtc->dev;
	priv = dev->dev_private;

	if (!priv->kms) {
		SDE_ERROR("invalid kms\n");
	if (enable) {
		if (_sde_crtc_power_enable(sde_crtc, true))
			return;
	}
	sde_kms = to_sde_kms(priv->kms);

	if (enable) {
		sde_power_resource_enable(&priv->phandle,
				sde_kms->core_client, true);
		list_for_each_entry(enc, &dev->mode_config.encoder_list, head) {
			if (enc->crtc != crtc)
				continue;
@@ -1125,8 +1148,7 @@ static void _sde_crtc_vblank_enable_nolock(

			sde_encoder_register_vblank_callback(enc, NULL, NULL);
		}
		sde_power_resource_enable(&priv->phandle,
				sde_kms->core_client, false);
		_sde_crtc_power_enable(sde_crtc, false);
	}
}

@@ -2001,6 +2023,107 @@ static int _sde_debugfs_status_open(struct inode *inode, struct file *file)
	return single_open(file, _sde_debugfs_status_show, inode->i_private);
}

static ssize_t _sde_crtc_misr_setup(struct file *file,
		const char __user *user_buf, size_t count, loff_t *ppos)
{
	struct sde_crtc *sde_crtc;
	struct sde_crtc_mixer *m;
	int i = 0, rc;
	char buf[MISR_BUFF_SIZE + 1];
	u32 frame_count, enable;
	size_t buff_copy;

	if (!file || !file->private_data)
		return -EINVAL;

	sde_crtc = file->private_data;
	buff_copy = min_t(size_t, count, MISR_BUFF_SIZE);
	if (copy_from_user(buf, user_buf, buff_copy)) {
		SDE_ERROR("buffer copy failed\n");
		return -EINVAL;
	}

	buf[buff_copy] = 0; /* end of string */

	if (sscanf(buf, "%u %u", &enable, &frame_count) != 2)
		return -EINVAL;

	rc = _sde_crtc_power_enable(sde_crtc, true);
	if (rc)
		return rc;

	mutex_lock(&sde_crtc->crtc_lock);
	sde_crtc->misr_enable = enable;
	for (i = 0; i < sde_crtc->num_mixers; ++i) {
		m = &sde_crtc->mixers[i];
		if (!m->hw_lm)
			continue;

		m->hw_lm->ops.setup_misr(m->hw_lm, enable, frame_count);
	}
	mutex_unlock(&sde_crtc->crtc_lock);
	_sde_crtc_power_enable(sde_crtc, false);

	return count;
}

static ssize_t _sde_crtc_misr_read(struct file *file,
		char __user *user_buff, size_t count, loff_t *ppos)
{
	struct sde_crtc *sde_crtc;
	struct sde_crtc_mixer *m;
	int i = 0, rc;
	ssize_t len = 0;
	char buf[MISR_BUFF_SIZE + 1] = {'\0'};

	if (*ppos)
		return 0;

	if (!file || !file->private_data)
		return -EINVAL;

	sde_crtc = file->private_data;
	rc = _sde_crtc_power_enable(sde_crtc, true);
	if (rc)
		return rc;

	mutex_lock(&sde_crtc->crtc_lock);
	if (!sde_crtc->misr_enable) {
		len += snprintf(buf + len, MISR_BUFF_SIZE - len,
			"disabled\n");
		goto buff_check;
	}

	for (i = 0; i < sde_crtc->num_mixers; ++i) {
		m = &sde_crtc->mixers[i];
		if (!m->hw_lm)
			continue;

		len += snprintf(buf + len, MISR_BUFF_SIZE - len, "lm idx:%d\n",
					m->hw_lm->idx - LM_0);
		len += snprintf(buf + len, MISR_BUFF_SIZE - len, "0x%x\n",
				m->hw_lm->ops.collect_misr(m->hw_lm));
	}

buff_check:
	if (count <= len) {
		len = 0;
		goto end;
	}

	if (copy_to_user(user_buff, buf, len)) {
		len = -EFAULT;
		goto end;
	}

	*ppos += len;   /* increase offset */

end:
	mutex_unlock(&sde_crtc->crtc_lock);
	_sde_crtc_power_enable(sde_crtc, false);
	return len;
}

#define DEFINE_SDE_DEBUGFS_SEQ_FOPS(__prefix)                          \
static int __prefix ## _open(struct inode *inode, struct file *file)	\
{									\
@@ -2042,6 +2165,11 @@ static int _sde_crtc_init_debugfs(struct drm_crtc *crtc)
		.llseek =	seq_lseek,
		.release =	single_release,
	};
	static const struct file_operations debugfs_misr_fops = {
		.open =		simple_open,
		.read =		_sde_crtc_misr_read,
		.write =	_sde_crtc_misr_setup,
	};

	if (!crtc)
		return -EINVAL;
@@ -2064,6 +2192,8 @@ static int _sde_crtc_init_debugfs(struct drm_crtc *crtc)
			sde_crtc->debugfs_root,
			&sde_crtc->base,
			&sde_crtc_debugfs_state_fops);
	debugfs_create_file("misr_data", 0644, sde_crtc->debugfs_root,
					sde_crtc, &debugfs_misr_fops);

	return 0;
}
+2 −0
Original line number Diff line number Diff line
@@ -136,6 +136,7 @@ struct sde_crtc_event {
 * @event_cache   : Local cache of event worker structures
 * @event_free_list : List of available event structures
 * @event_lock    : Spinlock around event handling code
 * @misr_enable   : boolean entry indicates misr enable/disable status.
 */
struct sde_crtc {
	struct drm_crtc base;
@@ -183,6 +184,7 @@ struct sde_crtc {
	struct sde_crtc_event event_cache[SDE_CRTC_MAX_EVENT_COUNT];
	struct list_head event_free_list;
	spinlock_t event_lock;
	bool misr_enable;
};

#define to_sde_crtc(x) container_of(x, struct sde_crtc, base)
+104 −73
Original line number Diff line number Diff line
@@ -57,6 +57,8 @@

#define MAX_CHANNELS_PER_ENC 2

#define MISR_BUFF_SIZE			256

/**
 * struct sde_encoder_virt - virtual encoder. Container of one or more physical
 *	encoders. Virtual encoder manages one "logical" display. Physical
@@ -90,6 +92,7 @@
 * @crtc_frame_event:		callback event
 * @frame_done_timeout:		frame done timeout in Hz
 * @frame_done_timer:		watchdog timer for frame done event
 * @misr_enable:		misr enable/disable status
 */
struct sde_encoder_virt {
	struct drm_encoder base;
@@ -120,6 +123,7 @@ struct sde_encoder_virt {
	struct sde_rsc_client *rsc_client;
	struct msm_display_info disp_info;
	bool rsc_state_update;
	bool misr_enable;
};

#define to_sde_encoder_virt(x) container_of(x, struct sde_encoder_virt, base)
@@ -131,6 +135,36 @@ inline bool _sde_is_dsc_enabled(struct sde_encoder_virt *sde_enc)
	return (comp_info->comp_type == MSM_DISPLAY_COMPRESSION_DSC);
}

static inline int _sde_encoder_power_enable(struct sde_encoder_virt *sde_enc,
								bool enable)
{
	struct drm_encoder *drm_enc;
	struct msm_drm_private *priv;
	struct sde_kms *sde_kms;

	if (!sde_enc) {
		SDE_ERROR("invalid sde enc\n");
		return -EINVAL;
	}

	drm_enc = &sde_enc->base;
	if (!drm_enc->dev || !drm_enc->dev->dev_private) {
		SDE_ERROR("drm device invalid\n");
		return -EINVAL;
	}

	priv = drm_enc->dev->dev_private;
	if (!priv->kms) {
		SDE_ERROR("invalid kms\n");
		return -EINVAL;
	}

	sde_kms = to_sde_kms(priv->kms);

	return sde_power_resource_enable(&priv->phandle, sde_kms->core_client,
									enable);
}

void sde_encoder_get_hw_resources(struct drm_encoder *drm_enc,
		struct sde_encoder_hw_resources *hw_res,
		struct drm_connector_state *conn_state)
@@ -706,8 +740,6 @@ static void sde_encoder_virt_mode_set(struct drm_encoder *drm_enc,
static void sde_encoder_virt_enable(struct drm_encoder *drm_enc)
{
	struct sde_encoder_virt *sde_enc = NULL;
	struct msm_drm_private *priv;
	struct sde_kms *sde_kms;
	int i = 0;
	int ret = 0;

@@ -723,13 +755,13 @@ static void sde_encoder_virt_enable(struct drm_encoder *drm_enc)
	}

	sde_enc = to_sde_encoder_virt(drm_enc);
	priv = drm_enc->dev->dev_private;
	sde_kms = to_sde_kms(priv->kms);

	SDE_DEBUG_ENC(sde_enc, "\n");
	SDE_EVT32(DRMID(drm_enc));

	sde_power_resource_enable(&priv->phandle, sde_kms->core_client, true);
	ret = _sde_encoder_power_enable(sde_enc, true);
	if (ret)
		return;

	sde_enc->cur_master = NULL;

@@ -810,7 +842,7 @@ static void sde_encoder_virt_disable(struct drm_encoder *drm_enc)

	sde_rm_release(&sde_kms->rm, drm_enc);

	sde_power_resource_enable(&priv->phandle, sde_kms->core_client, false);
	_sde_encoder_power_enable(sde_enc, false);
}

static enum sde_intf sde_encoder_get_intf(struct sde_mdss_cfg *catalog,
@@ -1389,105 +1421,108 @@ static int _sde_encoder_debugfs_status_open(struct inode *inode,
	return single_open(file, _sde_encoder_status_show, inode->i_private);
}

static void _sde_set_misr_params(struct sde_encoder_phys *phys, u32 enable,
					u32 frame_count)
{
	int j;

	if (!phys->misr_map)
		return;

	phys->misr_map->enable = enable;

	if (frame_count <= SDE_CRC_BATCH_SIZE)
		phys->misr_map->frame_count = frame_count;
	else if (frame_count <= 0)
		phys->misr_map->frame_count = 0;
	else
		phys->misr_map->frame_count = SDE_CRC_BATCH_SIZE;

	if (!enable) {
		phys->misr_map->last_idx = 0;
		phys->misr_map->frame_count = 0;
		for (j = 0; j < SDE_CRC_BATCH_SIZE; j++)
			phys->misr_map->crc_value[j] = 0;
	}
}

static ssize_t _sde_encoder_misr_set(struct file *file,
static ssize_t _sde_encoder_misr_setup(struct file *file,
		const char __user *user_buf, size_t count, loff_t *ppos)
{
	struct sde_encoder_virt *sde_enc;
	struct drm_encoder *drm_enc;
	int i = 0;
	char buf[10];
	u32 enable, frame_count;
	int i = 0, rc;
	char buf[MISR_BUFF_SIZE + 1];
	size_t buff_copy;
	u32 frame_count, enable;

	drm_enc = file->private_data;
	sde_enc = to_sde_encoder_virt(drm_enc);
	if (!file || !file->private_data)
		return -EINVAL;

	if (copy_from_user(buf, user_buf, count))
		return -EFAULT;
	sde_enc = file->private_data;

	buf[count] = 0; /* end of string */
	buff_copy = min_t(size_t, count, MISR_BUFF_SIZE);
	if (copy_from_user(buf, user_buf, buff_copy))
		return -EINVAL;

	buf[buff_copy] = 0; /* end of string */

	if (sscanf(buf, "%u %u", &enable, &frame_count) != 2)
		return -EFAULT;
		return -EINVAL;

	rc = _sde_encoder_power_enable(sde_enc, true);
	if (rc)
		return rc;

	mutex_lock(&sde_enc->enc_lock);
	sde_enc->misr_enable = enable;
	for (i = 0; i < sde_enc->num_phys_encs; i++) {
		struct sde_encoder_phys *phys = sde_enc->phys_encs[i];

		if (!phys || !phys->misr_map || !phys->ops.setup_misr)
		if (!phys || !phys->ops.setup_misr)
			continue;

		_sde_set_misr_params(phys, enable, frame_count);
		phys->ops.setup_misr(phys, phys->misr_map);
		phys->ops.setup_misr(phys, enable, frame_count);
	}
	mutex_unlock(&sde_enc->enc_lock);
	_sde_encoder_power_enable(sde_enc, false);

	return count;
}

static ssize_t _sde_encoder_misr_read(
		struct file *file,
		char __user *buff, size_t count, loff_t *ppos)
static ssize_t _sde_encoder_misr_read(struct file *file,
		char __user *user_buff, size_t count, loff_t *ppos)
{
	struct sde_encoder_virt *sde_enc;
	struct drm_encoder *drm_enc;
	int i = 0, j = 0, len = 0;
	char buf[512] = {'\0'};
	int i = 0, len = 0;
	char buf[MISR_BUFF_SIZE + 1] = {'\0'};
	int rc;

	if (*ppos)
		return 0;

	drm_enc = file->private_data;
	sde_enc = to_sde_encoder_virt(drm_enc);
	if (!file || !file->private_data)
		return -EINVAL;

	sde_enc = file->private_data;

	rc = _sde_encoder_power_enable(sde_enc, true);
	if (rc)
		return rc;

	mutex_lock(&sde_enc->enc_lock);
	if (!sde_enc->misr_enable) {
		len += snprintf(buf + len, MISR_BUFF_SIZE - len,
			"disabled\n");
		goto buff_check;
	} else if (sde_enc->disp_info.capabilities &
						~MSM_DISPLAY_CAP_VID_MODE) {
		len += snprintf(buf + len, MISR_BUFF_SIZE - len,
			"unsupported\n");
		goto buff_check;
	}

	for (i = 0; i < sde_enc->num_phys_encs; i++) {
		struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
		struct sde_misr_params *misr_map;

		if (!phys || !phys->misr_map)
		if (!phys || !phys->ops.collect_misr)
			continue;

		misr_map = phys->misr_map;

		len += snprintf(buf+len, sizeof(buf), "INTF%d\n", i);
		for (j = 0; j < SDE_CRC_BATCH_SIZE; j++)
			len += snprintf(buf+len, sizeof(buf), "%x\n",
						misr_map->crc_value[j]);
		len += snprintf(buf + len, MISR_BUFF_SIZE - len,
			"Intf idx:%d\n", phys->intf_idx - INTF_0);
		len += snprintf(buf + len, MISR_BUFF_SIZE - len, "0x%x\n",
					phys->ops.collect_misr(phys));
	}

	if (len < 0 || len >= sizeof(buf))
		return 0;
buff_check:
	if (count <= len) {
		len = 0;
		goto end;
	}

	if ((count < sizeof(buf)) || copy_to_user(buff, buf, len))
		return -EFAULT;
	if (copy_to_user(user_buff, buf, len)) {
		len = -EFAULT;
		goto end;
	}

	*ppos += len;   /* increase offset */
	mutex_unlock(&sde_enc->enc_lock);

end:
	mutex_unlock(&sde_enc->enc_lock);
	_sde_encoder_power_enable(sde_enc, false);
	return len;
}

@@ -1507,7 +1542,7 @@ static int _sde_encoder_init_debugfs(struct drm_encoder *drm_enc)
	static const struct file_operations debugfs_misr_fops = {
		.open = simple_open,
		.read = _sde_encoder_misr_read,
		.write = _sde_encoder_misr_set,
		.write = _sde_encoder_misr_setup,
	};

	char name[SDE_NAME_SIZE];
@@ -1534,7 +1569,7 @@ static int _sde_encoder_init_debugfs(struct drm_encoder *drm_enc)
		sde_enc->debugfs_root, sde_enc, &debugfs_status_fops);

	debugfs_create_file("misr_data", 0644,
		sde_enc->debugfs_root, drm_enc, &debugfs_misr_fops);
		sde_enc->debugfs_root, sde_enc, &debugfs_misr_fops);

	return 0;
}
@@ -1896,10 +1931,6 @@ int sde_encoder_wait_for_commit_done(struct drm_encoder *drm_enc)
			if (ret)
				return ret;
		}

		if (phys && phys->ops.collect_misr)
			if (phys->misr_map && phys->misr_map->enable)
				phys->ops.collect_misr(phys, phys->misr_map);
	}

	return ret;
+2 −5
Original line number Diff line number Diff line
@@ -148,9 +148,8 @@ struct sde_encoder_phys_ops {
	bool (*needs_single_flush)(struct sde_encoder_phys *phys_enc);

	void (*setup_misr)(struct sde_encoder_phys *phys_encs,
			struct sde_misr_params *misr_map);
	void (*collect_misr)(struct sde_encoder_phys *phys_enc,
			struct sde_misr_params *misr_map);
				bool enable, u32 frame_count);
	u32 (*collect_misr)(struct sde_encoder_phys *phys_enc);
	void (*hw_reset)(struct sde_encoder_phys *phys_enc);
};

@@ -184,7 +183,6 @@ enum sde_intr_idx {
 * @hw_pp:		Hardware interface to the ping pong registers
 * @sde_kms:		Pointer to the sde_kms top level
 * @cached_mode:	DRM mode cached at mode_set time, acted on in enable
 * @misr_map:		Interface for setting and collecting MISR data
 * @enabled:		Whether the encoder has enabled and running a mode
 * @split_role:		Role to play in a split-panel configuration
 * @intf_mode:		Interface mode
@@ -213,7 +211,6 @@ struct sde_encoder_phys {
	struct sde_hw_pingpong *hw_pp;
	struct sde_kms *sde_kms;
	struct drm_display_mode cached_mode;
	struct sde_misr_params *misr_map;
	enum sde_enc_split_role split_role;
	enum sde_intf_mode intf_mode;
	enum sde_intf intf_idx;
+17 −18
Original line number Diff line number Diff line
@@ -830,23 +830,29 @@ static void sde_encoder_phys_vid_handle_post_kickoff(
}

static void sde_encoder_phys_vid_setup_misr(struct sde_encoder_phys *phys_enc,
			struct sde_misr_params *misr_map)
						bool enable, u32 frame_count)
{
	struct sde_encoder_phys_vid *vid_enc =
		to_sde_encoder_phys_vid(phys_enc);
	struct sde_encoder_phys_vid *vid_enc;

	if (!phys_enc)
		return;
	vid_enc = to_sde_encoder_phys_vid(phys_enc);

	if (vid_enc && vid_enc->hw_intf && vid_enc->hw_intf->ops.setup_misr)
		vid_enc->hw_intf->ops.setup_misr(vid_enc->hw_intf, misr_map);
	if (vid_enc->hw_intf && vid_enc->hw_intf->ops.setup_misr)
		vid_enc->hw_intf->ops.setup_misr(vid_enc->hw_intf,
							enable, frame_count);
}

static void sde_encoder_phys_vid_collect_misr(struct sde_encoder_phys *phys_enc,
			struct sde_misr_params *misr_map)
static u32 sde_encoder_phys_vid_collect_misr(struct sde_encoder_phys *phys_enc)
{
	struct sde_encoder_phys_vid *vid_enc =
			to_sde_encoder_phys_vid(phys_enc);
	struct sde_encoder_phys_vid *vid_enc;

	if (!phys_enc)
		return 0;
	vid_enc = to_sde_encoder_phys_vid(phys_enc);

	if (vid_enc && vid_enc->hw_intf && vid_enc->hw_intf->ops.collect_misr)
		vid_enc->hw_intf->ops.collect_misr(vid_enc->hw_intf, misr_map);
	return vid_enc->hw_intf && vid_enc->hw_intf->ops.collect_misr ?
		vid_enc->hw_intf->ops.collect_misr(vid_enc->hw_intf) : 0;
}

static void sde_encoder_phys_vid_init_ops(struct sde_encoder_phys_ops *ops)
@@ -919,13 +925,6 @@ struct sde_encoder_phys *sde_encoder_phys_vid_init(
		goto fail;
	}

	phys_enc->misr_map = kzalloc(sizeof(struct sde_misr_params),
						GFP_KERNEL);
	if (!phys_enc->misr_map) {
		ret = -ENOMEM;
		goto fail;
	}

	SDE_DEBUG_VIDENC(vid_enc, "\n");

	sde_encoder_phys_vid_init_ops(&phys_enc->ops);
Loading