240 lines · 6.1 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-only/* * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt)"[drm-dp] %s: " fmt, __func__ #ifdef CONFIG_DEBUG_FS #include <linux/debugfs.h>#include <drm/drm_connector.h>#include <drm/drm_file.h> #include "dp_aux.h"#include "dp_ctrl.h"#include "dp_debug.h"#include "dp_display.h" #define DEBUG_NAME "msm_dp" struct msm_dp_debug_private {	struct msm_dp_link *link;	struct msm_dp_panel *panel;	struct drm_connector *connector;}; static int msm_dp_debug_show(struct seq_file *seq, void *p){	struct msm_dp_debug_private *debug = seq->private;	u64 lclk = 0;	u32 link_params_rate;	const struct drm_display_mode *drm_mode; 	if (!debug)		return -ENODEV; 	drm_mode = &debug->panel->msm_dp_mode.drm_mode; 	seq_printf(seq, "\tname = %s\n", DEBUG_NAME);	seq_printf(seq, "\tdrm_dp_link\n\t\trate = %u\n",			debug->panel->link_info.rate);	seq_printf(seq, "\t\tnum_lanes = %u\n",			debug->panel->link_info.num_lanes);	seq_printf(seq, "\t\tcapabilities = %lu\n",			debug->panel->link_info.capabilities);	seq_printf(seq, "\tdp_panel_info:\n\t\tactive = %dx%d\n",			drm_mode->hdisplay,			drm_mode->vdisplay);	seq_printf(seq, "\t\tback_porch = %dx%d\n",			drm_mode->htotal - drm_mode->hsync_end,			drm_mode->vtotal - drm_mode->vsync_end);	seq_printf(seq, "\t\tfront_porch = %dx%d\n",			drm_mode->hsync_start - drm_mode->hdisplay,			drm_mode->vsync_start - drm_mode->vdisplay);	seq_printf(seq, "\t\tsync_width = %dx%d\n",			drm_mode->hsync_end - drm_mode->hsync_start,			drm_mode->vsync_end - drm_mode->vsync_start);	seq_printf(seq, "\t\tactive_low = %dx%d\n",			debug->panel->msm_dp_mode.h_active_low,			debug->panel->msm_dp_mode.v_active_low);	seq_printf(seq, "\t\th_skew = %d\n",			drm_mode->hskew);	seq_printf(seq, "\t\trefresh rate = %d\n",			drm_mode_vrefresh(drm_mode));	seq_printf(seq, "\t\tpixel clock khz = %d\n",			drm_mode->clock);	seq_printf(seq, "\t\tbpp = %d\n",			debug->panel->msm_dp_mode.bpp); 	/* Link Information */	seq_printf(seq, "\tdp_link:\n\t\ttest_requested = %d\n",			debug->link->sink_request);	seq_printf(seq, "\t\tnum_lanes = %d\n",			debug->link->link_params.num_lanes);	link_params_rate = debug->link->link_params.rate;	seq_printf(seq, "\t\tbw_code = %d\n",			drm_dp_link_rate_to_bw_code(link_params_rate));	lclk = debug->link->link_params.rate * 1000;	seq_printf(seq, "\t\tlclk = %lld\n", lclk);	seq_printf(seq, "\t\tv_level = %d\n",			debug->link->phy_params.v_level);	seq_printf(seq, "\t\tp_level = %d\n",			debug->link->phy_params.p_level); 	return 0;}DEFINE_SHOW_ATTRIBUTE(msm_dp_debug); static int msm_dp_test_data_show(struct seq_file *m, void *data){	const struct msm_dp_debug_private *debug = m->private;	const struct drm_connector *connector = debug->connector;	u32 bpc; 	if (connector->status == connector_status_connected) {		bpc = debug->link->test_video.test_bit_depth;		seq_printf(m, "hdisplay: %d\n",				debug->link->test_video.test_h_width);		seq_printf(m, "vdisplay: %d\n",				debug->link->test_video.test_v_height);		seq_printf(m, "bpc: %u\n",				msm_dp_link_bit_depth_to_bpp(bpc) / 3);	} else {		seq_puts(m, "0");	} 	return 0;}DEFINE_SHOW_ATTRIBUTE(msm_dp_test_data); static int msm_dp_test_type_show(struct seq_file *m, void *data){	const struct msm_dp_debug_private *debug = m->private;	const struct drm_connector *connector = debug->connector; 	if (connector->status == connector_status_connected)		seq_printf(m, "%02x", DP_TEST_LINK_VIDEO_PATTERN);	else		seq_puts(m, "0"); 	return 0;}DEFINE_SHOW_ATTRIBUTE(msm_dp_test_type); static ssize_t msm_dp_test_active_write(struct file *file,		const char __user *ubuf,		size_t len, loff_t *offp){	char *input_buffer;	int status = 0;	const struct msm_dp_debug_private *debug;	const struct drm_connector *connector;	int val = 0; 	debug = ((struct seq_file *)file->private_data)->private;	connector = debug->connector; 	if (len == 0)		return 0; 	input_buffer = memdup_user_nul(ubuf, len);	if (IS_ERR(input_buffer))		return PTR_ERR(input_buffer); 	DRM_DEBUG_DRIVER("Copied %d bytes from user\n", (unsigned int)len); 	if (connector->status == connector_status_connected) {		status = kstrtoint(input_buffer, 10, &val);		if (status < 0) {			kfree(input_buffer);			return status;		}		DRM_DEBUG_DRIVER("Got %d for test active\n", val);		/* To prevent erroneous activation of the compliance		 * testing code, only accept an actual value of 1 here		 */		if (val == 1)			debug->panel->video_test = true;		else			debug->panel->video_test = false;	}	kfree(input_buffer); 	*offp += len;	return len;} static int msm_dp_test_active_show(struct seq_file *m, void *data){	struct msm_dp_debug_private *debug = m->private;	struct drm_connector *connector = debug->connector; 	if (connector->status == connector_status_connected) {		if (debug->panel->video_test)			seq_puts(m, "1");		else			seq_puts(m, "0");	} else {		seq_puts(m, "0");	} 	return 0;} static int msm_dp_test_active_open(struct inode *inode,		struct file *file){	return single_open(file, msm_dp_test_active_show,			inode->i_private);} static const struct file_operations test_active_fops = {	.owner = THIS_MODULE,	.open = msm_dp_test_active_open,	.read = seq_read,	.llseek = seq_lseek,	.release = single_release,	.write = msm_dp_test_active_write}; int msm_dp_debug_init(struct device *dev, struct msm_dp_panel *panel,		  struct msm_dp_link *link,		  struct drm_connector *connector,		  struct dentry *root, bool is_edp){	struct msm_dp_debug_private *debug; 	if (!dev || !panel || !link) {		DRM_ERROR("invalid input\n");		return -EINVAL;	} 	debug = devm_kzalloc(dev, sizeof(*debug), GFP_KERNEL);	if (!debug)		return -ENOMEM; 	debug->link = link;	debug->panel = panel; 	debugfs_create_file("dp_debug", 0444, root,			debug, &msm_dp_debug_fops); 	if (!is_edp) {		debugfs_create_file("dp_test_active", 0444,				    root,				    debug, &test_active_fops); 		debugfs_create_file("dp_test_data", 0444,				    root,				    debug, &msm_dp_test_data_fops); 		debugfs_create_file("dp_test_type", 0444,				    root,				    debug, &msm_dp_test_type_fops);	} 	return 0;} #endif