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

Commit a82752e1 authored by Thierry Reding's avatar Thierry Reding
Browse files

drm/tegra: sor - Add CRC debugfs support



The SOR allows the computation of a 32 bit CRC of the content that it
transmits. This functionality is exposed via debugfs and is useful to
verify proper operation of the SOR.

Signed-off-by: default avatarThierry Reding <treding@nvidia.com>
parent f925390e
Loading
Loading
Loading
Loading
+121 −0
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@
 */

#include <linux/clk.h>
#include <linux/debugfs.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
@@ -34,6 +35,8 @@ struct tegra_sor {
	struct tegra_dpaux *dpaux;

	bool enabled;

	struct dentry *debugfs;
};

static inline struct tegra_sor *
@@ -914,6 +917,110 @@ static const struct tegra_output_ops sor_ops = {
	.detect = tegra_output_sor_detect,
};

static int tegra_sor_crc_open(struct inode *inode, struct file *file)
{
	file->private_data = inode->i_private;

	return 0;
}

static int tegra_sor_crc_release(struct inode *inode, struct file *file)
{
	return 0;
}

static int tegra_sor_crc_wait(struct tegra_sor *sor, unsigned long timeout)
{
	u32 value;

	timeout = jiffies + msecs_to_jiffies(timeout);

	while (time_before(jiffies, timeout)) {
		value = tegra_sor_readl(sor, SOR_CRC_A);
		if (value & SOR_CRC_A_VALID)
			return 0;

		usleep_range(100, 200);
	}

	return -ETIMEDOUT;
}

static ssize_t tegra_sor_crc_read(struct file *file, char __user *buffer,
				  size_t size, loff_t *ppos)
{
	struct tegra_sor *sor = file->private_data;
	char buf[10];
	ssize_t num;
	u32 value;
	int err;

	value = tegra_sor_readl(sor, SOR_STATE_1);
	value &= ~SOR_STATE_ASY_CRC_MODE_MASK;
	tegra_sor_writel(sor, value, SOR_STATE_1);

	value = tegra_sor_readl(sor, SOR_CRC_CNTRL);
	value |= SOR_CRC_CNTRL_ENABLE;
	tegra_sor_writel(sor, value, SOR_CRC_CNTRL);

	value = tegra_sor_readl(sor, SOR_TEST);
	value &= ~SOR_TEST_CRC_POST_SERIALIZE;
	tegra_sor_writel(sor, value, SOR_TEST);

	err = tegra_sor_crc_wait(sor, 100);
	if (err < 0)
		return err;

	tegra_sor_writel(sor, SOR_CRC_A_RESET, SOR_CRC_A);
	value = tegra_sor_readl(sor, SOR_CRC_B);

	num = scnprintf(buf, sizeof(buf), "%08x\n", value);

	return simple_read_from_buffer(buffer, size, ppos, buf, num);
}

static const struct file_operations tegra_sor_crc_fops = {
	.owner = THIS_MODULE,
	.open = tegra_sor_crc_open,
	.read = tegra_sor_crc_read,
	.release = tegra_sor_crc_release,
};

static int tegra_sor_debugfs_init(struct tegra_sor *sor, struct dentry *root)
{
	struct dentry *entry;
	int err = 0;

	sor->debugfs = debugfs_create_dir("sor", root);
	if (!sor->debugfs)
		return -ENOMEM;

	entry = debugfs_create_file("crc", 0644, sor->debugfs, sor,
				    &tegra_sor_crc_fops);
	if (!entry) {
		dev_err(sor->dev,
			"cannot create /sys/kernel/debug/dri/%s/sor/crc\n",
			root->d_name.name);
		err = -ENOMEM;
		goto remove;
	}

	return err;

remove:
	debugfs_remove(sor->debugfs);
	sor->debugfs = NULL;
	return err;
}

static int tegra_sor_debugfs_exit(struct tegra_sor *sor)
{
	debugfs_remove(sor->debugfs);
	sor->debugfs = NULL;

	return 0;
}

static int tegra_sor_init(struct host1x_client *client)
{
	struct tegra_drm *tegra = dev_get_drvdata(client->parent);
@@ -934,6 +1041,14 @@ static int tegra_sor_init(struct host1x_client *client)
		return err;
	}

	if (IS_ENABLED(CONFIG_DEBUG_FS)) {
		struct dentry *root = tegra->drm->primary->debugfs_root;

		err = tegra_sor_debugfs_init(sor, root);
		if (err < 0)
			dev_err(sor->dev, "debugfs setup failed: %d\n", err);
	}

	if (sor->dpaux) {
		err = tegra_dpaux_attach(sor->dpaux, &sor->output);
		if (err < 0) {
@@ -964,6 +1079,12 @@ static int tegra_sor_exit(struct host1x_client *client)
		}
	}

	if (IS_ENABLED(CONFIG_DEBUG_FS)) {
		err = tegra_sor_debugfs_exit(sor);
		if (err < 0)
			dev_err(sor->dev, "debugfs cleanup failed: %d\n", err);
	}

	err = tegra_output_exit(&sor->output);
	if (err < 0) {
		dev_err(sor->dev, "output cleanup failed: %d\n", err);
+4 −0
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@
#define SOR_HEAD_STATE_4(x) (0x0d + (x))
#define SOR_HEAD_STATE_5(x) (0x0f + (x))
#define SOR_CRC_CNTRL 0x11
#define  SOR_CRC_CNTRL_ENABLE			(1 << 0)
#define SOR_DP_DEBUG_MVID 0x12

#define SOR_CLK_CNTRL 0x13
@@ -69,6 +70,7 @@
#define  SOR_PWR_NORMAL_STATE_PU		(1 << 0)

#define SOR_TEST 0x16
#define  SOR_TEST_CRC_POST_SERIALIZE		(1 << 23)
#define  SOR_TEST_ATTACHED			(1 << 10)
#define  SOR_TEST_HEAD_MODE_MASK		(3 << 8)
#define  SOR_TEST_HEAD_MODE_AWAKE		(2 << 8)
@@ -115,6 +117,8 @@

#define SOR_LVDS 0x1c
#define SOR_CRC_A 0x1d
#define  SOR_CRC_A_VALID			(1 << 0)
#define  SOR_CRC_A_RESET			(1 << 0)
#define SOR_CRC_B 0x1e
#define SOR_BLANK 0x1f
#define SOR_SEQ_CTL 0x20