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

Commit f0fd8516 authored by Alan Kwong's avatar Alan Kwong Committed by Narendra Muppalla
Browse files

drm/msm/sde: add debugfs entry for danger and safe status



Add debugfs entry for current danger and safe status of each pipe
and current overall status for debugging purposes.

Change-Id: I3e784d0218df40c184a431409c864a3208a90b45
Signed-off-by: default avatarAlan Kwong <akwong@codeaurora.org>
parent 8e69ad00
Loading
Loading
Loading
Loading
+62 −0
Original line number Diff line number Diff line
@@ -22,6 +22,9 @@
#define FLD_INTF_2_SW_TRG_MUX             BIT(8)
#define FLD_TE_LINE_INTER_WATERLEVEL_MASK 0xFFFF

#define DANGER_STATUS                     0x360
#define SAFE_STATUS                       0x364

#define TE_LINE_INTERVAL                  0x3F4

#define TRAFFIC_SHAPER_EN                 BIT(31)
@@ -139,6 +142,63 @@ static bool sde_hw_setup_clk_force_ctrl(struct sde_hw_mdp *mdp,
	return clk_forced_on;
}


static void sde_hw_get_danger_status(struct sde_hw_mdp *mdp,
		struct sde_danger_safe_status *status)
{
	struct sde_hw_blk_reg_map *c = &mdp->hw;
	u32 value;

	value = SDE_REG_READ(c, DANGER_STATUS);
	status->mdp = (value >> 0) & 0x3;
	status->sspp[SSPP_VIG0] = (value >> 4) & 0x3;
	status->sspp[SSPP_VIG1] = (value >> 6) & 0x3;
	status->sspp[SSPP_VIG2] = (value >> 8) & 0x3;
	status->sspp[SSPP_VIG3] = (value >> 10) & 0x3;
	status->sspp[SSPP_RGB0] = (value >> 12) & 0x3;
	status->sspp[SSPP_RGB1] = (value >> 14) & 0x3;
	status->sspp[SSPP_RGB2] = (value >> 16) & 0x3;
	status->sspp[SSPP_RGB3] = (value >> 18) & 0x3;
	status->sspp[SSPP_DMA0] = (value >> 20) & 0x3;
	status->sspp[SSPP_DMA1] = (value >> 22) & 0x3;
	status->sspp[SSPP_DMA2] = (value >> 28) & 0x3;
	status->sspp[SSPP_DMA3] = (value >> 30) & 0x3;
	status->sspp[SSPP_CURSOR0] = (value >> 24) & 0x3;
	status->sspp[SSPP_CURSOR1] = (value >> 26) & 0x3;
	status->wb[WB_0] = 0;
	status->wb[WB_1] = 0;
	status->wb[WB_2] = (value >> 2) & 0x3;
	status->wb[WB_3] = 0;
}

static void sde_hw_get_safe_status(struct sde_hw_mdp *mdp,
		struct sde_danger_safe_status *status)
{
	struct sde_hw_blk_reg_map *c = &mdp->hw;
	u32 value;

	value = SDE_REG_READ(c, SAFE_STATUS);
	status->mdp = (value >> 0) & 0x1;
	status->sspp[SSPP_VIG0] = (value >> 4) & 0x1;
	status->sspp[SSPP_VIG1] = (value >> 6) & 0x1;
	status->sspp[SSPP_VIG2] = (value >> 8) & 0x1;
	status->sspp[SSPP_VIG3] = (value >> 10) & 0x1;
	status->sspp[SSPP_RGB0] = (value >> 12) & 0x1;
	status->sspp[SSPP_RGB1] = (value >> 14) & 0x1;
	status->sspp[SSPP_RGB2] = (value >> 16) & 0x1;
	status->sspp[SSPP_RGB3] = (value >> 18) & 0x1;
	status->sspp[SSPP_DMA0] = (value >> 20) & 0x1;
	status->sspp[SSPP_DMA1] = (value >> 22) & 0x1;
	status->sspp[SSPP_DMA2] = (value >> 28) & 0x1;
	status->sspp[SSPP_DMA3] = (value >> 30) & 0x1;
	status->sspp[SSPP_CURSOR0] = (value >> 24) & 0x1;
	status->sspp[SSPP_CURSOR1] = (value >> 26) & 0x1;
	status->wb[WB_0] = 0;
	status->wb[WB_1] = 0;
	status->wb[WB_2] = (value >> 2) & 0x1;
	status->wb[WB_3] = 0;
}

static void _setup_mdp_ops(struct sde_hw_mdp_ops *ops,
		unsigned long cap)
{
@@ -146,6 +206,8 @@ static void _setup_mdp_ops(struct sde_hw_mdp_ops *ops,
	ops->setup_pp_split = sde_hw_setup_pp_split;
	ops->setup_cdm_output = sde_hw_setup_cdm_output;
	ops->setup_clk_force_ctrl = sde_hw_setup_clk_force_ctrl;
	ops->get_danger_status = sde_hw_get_danger_status;
	ops->get_safe_status = sde_hw_get_safe_status;
}

static const struct sde_mdp_cfg *_top_offset(enum sde_mdp mdp,
+28 −0
Original line number Diff line number Diff line
@@ -64,6 +64,18 @@ struct cdm_output_cfg {
	bool intf_en;
};

/**
 * struct sde_danger_safe_status: danger and safe status signals
 * @mdp: top level status
 * @sspp: source pipe status
 * @wb: writebck output status
 */
struct sde_danger_safe_status {
	u8 mdp;
	u8 sspp[SSPP_MAX];
	u8 wb[WB_MAX];
};

/**
 * struct sde_hw_mdp_ops - interface to the MDP TOP Hw driver functions
 * Assumption is these functions will be called after clocks are enabled.
@@ -113,6 +125,22 @@ struct sde_hw_mdp_ops {
	 */
	bool (*setup_clk_force_ctrl)(struct sde_hw_mdp *mdp,
			enum sde_clk_ctrl_type clk_ctrl, bool enable);

	/**
	 * get_danger_status - get danger status
	 * @mdp: mdp top context driver
	 * @status: Pointer to danger safe status
	 */
	void (*get_danger_status)(struct sde_hw_mdp *mdp,
			struct sde_danger_safe_status *status);

	/**
	 * get_safe_status - get safe status
	 * @mdp: mdp top context driver
	 * @status: Pointer to danger safe status
	 */
	void (*get_safe_status)(struct sde_hw_mdp *mdp,
			struct sde_danger_safe_status *status);
};

struct sde_hw_mdp {
+110 −0
Original line number Diff line number Diff line
@@ -78,6 +78,101 @@ bool sde_is_custom_client(void)
	return sdecustom;
}

#ifdef CONFIG_DEBUG_FS
static int _sde_danger_signal_status(struct seq_file *s,
		bool danger_status)
{
	struct sde_kms *kms = (struct sde_kms *)s->private;
	struct msm_drm_private *priv;
	struct sde_danger_safe_status status;
	int i;

	if (!kms || !kms->dev || !kms->dev->dev_private || !kms->hw_mdp) {
		SDE_ERROR("invalid arg(s)\n");
		return 0;
	}

	priv = kms->dev->dev_private;
	memset(&status, 0, sizeof(struct sde_danger_safe_status));

	sde_power_resource_enable(&priv->phandle, kms->core_client, true);
	if (danger_status) {
		seq_puts(s, "\nDanger signal status:\n");
		if (kms->hw_mdp->ops.get_danger_status)
			kms->hw_mdp->ops.get_danger_status(kms->hw_mdp,
					&status);
	} else {
		seq_puts(s, "\nSafe signal status:\n");
		if (kms->hw_mdp->ops.get_danger_status)
			kms->hw_mdp->ops.get_danger_status(kms->hw_mdp,
					&status);
	}
	sde_power_resource_enable(&priv->phandle, kms->core_client, false);

	seq_printf(s, "MDP     :  0x%x\n", status.mdp);

	for (i = SSPP_VIG0; i < SSPP_MAX; i++)
		seq_printf(s, "SSPP%d   :  0x%x  \t", i - SSPP_VIG0,
				status.sspp[i]);
	seq_puts(s, "\n");

	for (i = WB_0; i < WB_MAX; i++)
		seq_printf(s, "WB%d     :  0x%x  \t", i - WB_0,
				status.wb[i]);
	seq_puts(s, "\n");

	return 0;
}

#define DEFINE_SDE_DEBUGFS_SEQ_FOPS(__prefix)				\
static int __prefix ## _open(struct inode *inode, struct file *file)	\
{									\
	return single_open(file, __prefix ## _show, inode->i_private);	\
}									\
static const struct file_operations __prefix ## _fops = {		\
	.owner = THIS_MODULE,						\
	.open = __prefix ## _open,					\
	.release = single_release,					\
	.read = seq_read,						\
	.llseek = seq_lseek,						\
}

static int sde_debugfs_danger_stats_show(struct seq_file *s, void *v)
{
	return _sde_danger_signal_status(s, true);
}
DEFINE_SDE_DEBUGFS_SEQ_FOPS(sde_debugfs_danger_stats);

static int sde_debugfs_safe_stats_show(struct seq_file *s, void *v)
{
	return _sde_danger_signal_status(s, false);
}
DEFINE_SDE_DEBUGFS_SEQ_FOPS(sde_debugfs_safe_stats);

static void sde_debugfs_danger_destroy(struct sde_kms *sde_kms)
{
	debugfs_remove_recursive(sde_kms->debugfs_danger);
	sde_kms->debugfs_danger = NULL;
}

static int sde_debugfs_danger_init(struct sde_kms *sde_kms,
		struct dentry *parent)
{
	sde_kms->debugfs_danger = debugfs_create_dir("danger",
			parent);
	if (!sde_kms->debugfs_danger) {
		SDE_ERROR("failed to create danger debugfs\n");
		return -EINVAL;
	}

	debugfs_create_file("danger_status", 0644, sde_kms->debugfs_danger,
			sde_kms, &sde_debugfs_danger_stats_fops);
	debugfs_create_file("safe_status", 0644, sde_kms->debugfs_danger,
			sde_kms, &sde_debugfs_safe_stats_fops);

	return 0;
}

static int _sde_debugfs_show_regset32(struct seq_file *s, void *data)
{
	struct sde_debugfs_regset32 *regset;
@@ -197,6 +292,8 @@ static int _sde_debugfs_init(struct sde_kms *sde_kms)
	if (!sde_kms->debugfs_debug)
		SDE_ERROR("failed to create debugfs debug directory\n");

	sde_debugfs_danger_init(sde_kms, sde_kms->debugfs_debug);

	return 0;
}

@@ -204,12 +301,25 @@ static void _sde_debugfs_destroy(struct sde_kms *sde_kms)
{
	/* don't need to NULL check debugfs_root */
	if (sde_kms) {
		sde_debugfs_danger_destroy(sde_kms);
		debugfs_remove_recursive(sde_kms->debugfs_debug);
		sde_kms->debugfs_debug = 0;
		debugfs_remove_recursive(sde_kms->debugfs_root);
		sde_kms->debugfs_root = 0;
	}
}
#else
static void sde_debugfs_danger_destroy(struct sde_kms *sde_kms,
		struct dentry *parent)
{
}

static int sde_debugfs_danger_init(struct sde_kms *sde_kms,
		struct dentry *parent)
{
	return 0;
}
#endif

static int sde_kms_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc)
{
+3 −0
Original line number Diff line number Diff line
@@ -121,6 +121,7 @@ struct sde_kms {
	/* directory entry for debugfs */
	void *debugfs_root;
	struct dentry *debugfs_debug;
	struct dentry *debugfs_danger;

	/* io/register spaces: */
	void __iomem *mmio, *vbif[VBIF_MAX];
@@ -143,6 +144,8 @@ struct sde_kms {
	void **dsi_displays;
	int wb_display_count;
	void **wb_displays;

	bool has_danger_ctrl;
};

struct vsync_info {
+147 −0
Original line number Diff line number Diff line
@@ -406,6 +406,39 @@ static void _sde_plane_set_qos_ctrl(struct drm_plane *plane,
			&psde->pipe_qos_cfg);
}

int sde_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable)
{
	struct sde_plane *psde;
	struct msm_drm_private *priv;
	struct sde_kms *sde_kms;

	if (!plane || !plane->dev) {
		SDE_ERROR("invalid arguments\n");
		return -EINVAL;
	}

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

	sde_kms = to_sde_kms(priv->kms);
	psde = to_sde_plane(plane);

	if (!psde->is_rt_pipe)
		goto end;

	sde_power_resource_enable(&priv->phandle, sde_kms->core_client, true);

	_sde_plane_set_qos_ctrl(plane, enable, SDE_PLANE_QOS_PANIC_CTRL);

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

end:
	return 0;
}

/**
 * _sde_plane_set_ot_limit - set OT limit for the given plane
 * @plane:		Pointer to drm plane
@@ -2069,6 +2102,98 @@ enum sde_sspp sde_plane_pipe(struct drm_plane *plane)
	return plane ? to_sde_plane(plane)->pipe : SSPP_NONE;
}

static ssize_t _sde_plane_danger_read(struct file *file,
			char __user *buff, size_t count, loff_t *ppos)
{
	struct sde_kms *kms = file->private_data;
	struct sde_mdss_cfg *cfg = kms->catalog;
	int len = 0;
	char buf[40] = {'\0'};

	if (!cfg)
		return -ENODEV;

	if (*ppos)
		return 0; /* the end */

	len = snprintf(buf, sizeof(buf), "%d\n", !kms->has_danger_ctrl);
	if (len < 0 || len >= sizeof(buf))
		return 0;

	if ((count < sizeof(buf)) || copy_to_user(buff, buf, len))
		return -EFAULT;

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

	return len;
}

static void _sde_plane_set_danger_state(struct sde_kms *kms, bool enable)
{
	struct drm_plane *plane;

	drm_for_each_plane(plane, kms->dev) {
		if (plane->fb && plane->state) {
			sde_plane_danger_signal_ctrl(plane, enable);
			SDE_DEBUG("plane:%d img:%dx%d ",
				plane->base.id, plane->fb->width,
				plane->fb->height);
			SDE_DEBUG("src[%d,%d,%d,%d] dst[%d,%d,%d,%d]\n",
				plane->state->src_x >> 16,
				plane->state->src_y >> 16,
				plane->state->src_w >> 16,
				plane->state->src_h >> 16,
				plane->state->crtc_x, plane->state->crtc_y,
				plane->state->crtc_w, plane->state->crtc_h);
		} else {
			SDE_DEBUG("Inactive plane:%d\n", plane->base.id);
		}
	}
}

static ssize_t _sde_plane_danger_write(struct file *file,
		    const char __user *user_buf, size_t count, loff_t *ppos)
{
	struct sde_kms *kms = file->private_data;
	struct sde_mdss_cfg *cfg = kms->catalog;
	int disable_panic;
	char buf[10];

	if (!cfg)
		return -EFAULT;

	if (count >= sizeof(buf))
		return -EFAULT;

	if (copy_from_user(buf, user_buf, count))
		return -EFAULT;

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

	if (kstrtoint(buf, 0, &disable_panic))
		return -EFAULT;

	if (disable_panic) {
		/* Disable panic signal for all active pipes */
		SDE_DEBUG("Disabling danger:\n");
		_sde_plane_set_danger_state(kms, false);
		kms->has_danger_ctrl = false;
	} else {
		/* Enable panic signal for all active pipes */
		SDE_DEBUG("Enabling danger:\n");
		kms->has_danger_ctrl = true;
		_sde_plane_set_danger_state(kms, true);
	}

	return count;
}

static const struct file_operations sde_plane_danger_enable = {
	.open = simple_open,
	.read = _sde_plane_danger_read,
	.write = _sde_plane_danger_write,
};

static void _sde_plane_init_debugfs(struct sde_plane *psde, struct sde_kms *kms)
{
	const struct sde_sspp_sub_blks *sblk = 0;
@@ -2111,6 +2236,28 @@ static void _sde_plane_init_debugfs(struct sde_plane *psde, struct sde_kms *kms)
					kms);
			sde_debugfs_create_regset32("csc_blk", 0444,
					psde->debugfs_root, &psde->debugfs_csc);

			debugfs_create_u32("xin_id",
					0444,
					psde->debugfs_root,
					(u32 *) &cfg->xin_id);
			debugfs_create_u32("clk_ctrl",
					0444,
					psde->debugfs_root,
					(u32 *) &cfg->clk_ctrl);
			debugfs_create_x32("creq_vblank",
					0644,
					psde->debugfs_root,
					(u32 *) &sblk->creq_vblank);
			debugfs_create_x32("danger_vblank",
					0644,
					psde->debugfs_root,
					(u32 *) &sblk->danger_vblank);

			debugfs_create_file("disable_danger",
					0644,
					psde->debugfs_root,
					kms, &sde_plane_danger_enable);
		}
	}
}