diff options
author | Thierry Reding <treding@nvidia.com> | 2014-01-31 04:02:15 -0500 |
---|---|---|
committer | Thierry Reding <treding@nvidia.com> | 2014-06-05 17:09:17 -0400 |
commit | a82752e19954cb741a7a582482e5c05c50d7acd3 (patch) | |
tree | f32dd92bc20b9060c8d6a4254c4068c94502ae09 | |
parent | f925390efccb24016a4fafe77721770021ed754a (diff) |
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: Thierry Reding <treding@nvidia.com>
-rw-r--r-- | drivers/gpu/drm/tegra/sor.c | 121 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/sor.h | 4 |
2 files changed, 125 insertions, 0 deletions
diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index 49ef5729f435..b2151ea679f0 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c | |||
@@ -7,6 +7,7 @@ | |||
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/clk.h> | 9 | #include <linux/clk.h> |
10 | #include <linux/debugfs.h> | ||
10 | #include <linux/io.h> | 11 | #include <linux/io.h> |
11 | #include <linux/platform_device.h> | 12 | #include <linux/platform_device.h> |
12 | #include <linux/reset.h> | 13 | #include <linux/reset.h> |
@@ -34,6 +35,8 @@ struct tegra_sor { | |||
34 | struct tegra_dpaux *dpaux; | 35 | struct tegra_dpaux *dpaux; |
35 | 36 | ||
36 | bool enabled; | 37 | bool enabled; |
38 | |||
39 | struct dentry *debugfs; | ||
37 | }; | 40 | }; |
38 | 41 | ||
39 | static inline struct tegra_sor * | 42 | static inline struct tegra_sor * |
@@ -914,6 +917,110 @@ static const struct tegra_output_ops sor_ops = { | |||
914 | .detect = tegra_output_sor_detect, | 917 | .detect = tegra_output_sor_detect, |
915 | }; | 918 | }; |
916 | 919 | ||
920 | static int tegra_sor_crc_open(struct inode *inode, struct file *file) | ||
921 | { | ||
922 | file->private_data = inode->i_private; | ||
923 | |||
924 | return 0; | ||
925 | } | ||
926 | |||
927 | static int tegra_sor_crc_release(struct inode *inode, struct file *file) | ||
928 | { | ||
929 | return 0; | ||
930 | } | ||
931 | |||
932 | static int tegra_sor_crc_wait(struct tegra_sor *sor, unsigned long timeout) | ||
933 | { | ||
934 | u32 value; | ||
935 | |||
936 | timeout = jiffies + msecs_to_jiffies(timeout); | ||
937 | |||
938 | while (time_before(jiffies, timeout)) { | ||
939 | value = tegra_sor_readl(sor, SOR_CRC_A); | ||
940 | if (value & SOR_CRC_A_VALID) | ||
941 | return 0; | ||
942 | |||
943 | usleep_range(100, 200); | ||
944 | } | ||
945 | |||
946 | return -ETIMEDOUT; | ||
947 | } | ||
948 | |||
949 | static ssize_t tegra_sor_crc_read(struct file *file, char __user *buffer, | ||
950 | size_t size, loff_t *ppos) | ||
951 | { | ||
952 | struct tegra_sor *sor = file->private_data; | ||
953 | char buf[10]; | ||
954 | ssize_t num; | ||
955 | u32 value; | ||
956 | int err; | ||
957 | |||
958 | value = tegra_sor_readl(sor, SOR_STATE_1); | ||
959 | value &= ~SOR_STATE_ASY_CRC_MODE_MASK; | ||
960 | tegra_sor_writel(sor, value, SOR_STATE_1); | ||
961 | |||
962 | value = tegra_sor_readl(sor, SOR_CRC_CNTRL); | ||
963 | value |= SOR_CRC_CNTRL_ENABLE; | ||
964 | tegra_sor_writel(sor, value, SOR_CRC_CNTRL); | ||
965 | |||
966 | value = tegra_sor_readl(sor, SOR_TEST); | ||
967 | value &= ~SOR_TEST_CRC_POST_SERIALIZE; | ||
968 | tegra_sor_writel(sor, value, SOR_TEST); | ||
969 | |||
970 | err = tegra_sor_crc_wait(sor, 100); | ||
971 | if (err < 0) | ||
972 | return err; | ||
973 | |||
974 | tegra_sor_writel(sor, SOR_CRC_A_RESET, SOR_CRC_A); | ||
975 | value = tegra_sor_readl(sor, SOR_CRC_B); | ||
976 | |||
977 | num = scnprintf(buf, sizeof(buf), "%08x\n", value); | ||
978 | |||
979 | return simple_read_from_buffer(buffer, size, ppos, buf, num); | ||
980 | } | ||
981 | |||
982 | static const struct file_operations tegra_sor_crc_fops = { | ||
983 | .owner = THIS_MODULE, | ||
984 | .open = tegra_sor_crc_open, | ||
985 | .read = tegra_sor_crc_read, | ||
986 | .release = tegra_sor_crc_release, | ||
987 | }; | ||
988 | |||
989 | static int tegra_sor_debugfs_init(struct tegra_sor *sor, struct dentry *root) | ||
990 | { | ||
991 | struct dentry *entry; | ||
992 | int err = 0; | ||
993 | |||
994 | sor->debugfs = debugfs_create_dir("sor", root); | ||
995 | if (!sor->debugfs) | ||
996 | return -ENOMEM; | ||
997 | |||
998 | entry = debugfs_create_file("crc", 0644, sor->debugfs, sor, | ||
999 | &tegra_sor_crc_fops); | ||
1000 | if (!entry) { | ||
1001 | dev_err(sor->dev, | ||
1002 | "cannot create /sys/kernel/debug/dri/%s/sor/crc\n", | ||
1003 | root->d_name.name); | ||
1004 | err = -ENOMEM; | ||
1005 | goto remove; | ||
1006 | } | ||
1007 | |||
1008 | return err; | ||
1009 | |||
1010 | remove: | ||
1011 | debugfs_remove(sor->debugfs); | ||
1012 | sor->debugfs = NULL; | ||
1013 | return err; | ||
1014 | } | ||
1015 | |||
1016 | static int tegra_sor_debugfs_exit(struct tegra_sor *sor) | ||
1017 | { | ||
1018 | debugfs_remove(sor->debugfs); | ||
1019 | sor->debugfs = NULL; | ||
1020 | |||
1021 | return 0; | ||
1022 | } | ||
1023 | |||
917 | static int tegra_sor_init(struct host1x_client *client) | 1024 | static int tegra_sor_init(struct host1x_client *client) |
918 | { | 1025 | { |
919 | struct tegra_drm *tegra = dev_get_drvdata(client->parent); | 1026 | struct tegra_drm *tegra = dev_get_drvdata(client->parent); |
@@ -934,6 +1041,14 @@ static int tegra_sor_init(struct host1x_client *client) | |||
934 | return err; | 1041 | return err; |
935 | } | 1042 | } |
936 | 1043 | ||
1044 | if (IS_ENABLED(CONFIG_DEBUG_FS)) { | ||
1045 | struct dentry *root = tegra->drm->primary->debugfs_root; | ||
1046 | |||
1047 | err = tegra_sor_debugfs_init(sor, root); | ||
1048 | if (err < 0) | ||
1049 | dev_err(sor->dev, "debugfs setup failed: %d\n", err); | ||
1050 | } | ||
1051 | |||
937 | if (sor->dpaux) { | 1052 | if (sor->dpaux) { |
938 | err = tegra_dpaux_attach(sor->dpaux, &sor->output); | 1053 | err = tegra_dpaux_attach(sor->dpaux, &sor->output); |
939 | if (err < 0) { | 1054 | if (err < 0) { |
@@ -964,6 +1079,12 @@ static int tegra_sor_exit(struct host1x_client *client) | |||
964 | } | 1079 | } |
965 | } | 1080 | } |
966 | 1081 | ||
1082 | if (IS_ENABLED(CONFIG_DEBUG_FS)) { | ||
1083 | err = tegra_sor_debugfs_exit(sor); | ||
1084 | if (err < 0) | ||
1085 | dev_err(sor->dev, "debugfs cleanup failed: %d\n", err); | ||
1086 | } | ||
1087 | |||
967 | err = tegra_output_exit(&sor->output); | 1088 | err = tegra_output_exit(&sor->output); |
968 | if (err < 0) { | 1089 | if (err < 0) { |
969 | dev_err(sor->dev, "output cleanup failed: %d\n", err); | 1090 | dev_err(sor->dev, "output cleanup failed: %d\n", err); |
diff --git a/drivers/gpu/drm/tegra/sor.h b/drivers/gpu/drm/tegra/sor.h index f4156d54cd05..a5f8853fedb5 100644 --- a/drivers/gpu/drm/tegra/sor.h +++ b/drivers/gpu/drm/tegra/sor.h | |||
@@ -47,6 +47,7 @@ | |||
47 | #define SOR_HEAD_STATE_4(x) (0x0d + (x)) | 47 | #define SOR_HEAD_STATE_4(x) (0x0d + (x)) |
48 | #define SOR_HEAD_STATE_5(x) (0x0f + (x)) | 48 | #define SOR_HEAD_STATE_5(x) (0x0f + (x)) |
49 | #define SOR_CRC_CNTRL 0x11 | 49 | #define SOR_CRC_CNTRL 0x11 |
50 | #define SOR_CRC_CNTRL_ENABLE (1 << 0) | ||
50 | #define SOR_DP_DEBUG_MVID 0x12 | 51 | #define SOR_DP_DEBUG_MVID 0x12 |
51 | 52 | ||
52 | #define SOR_CLK_CNTRL 0x13 | 53 | #define SOR_CLK_CNTRL 0x13 |
@@ -69,6 +70,7 @@ | |||
69 | #define SOR_PWR_NORMAL_STATE_PU (1 << 0) | 70 | #define SOR_PWR_NORMAL_STATE_PU (1 << 0) |
70 | 71 | ||
71 | #define SOR_TEST 0x16 | 72 | #define SOR_TEST 0x16 |
73 | #define SOR_TEST_CRC_POST_SERIALIZE (1 << 23) | ||
72 | #define SOR_TEST_ATTACHED (1 << 10) | 74 | #define SOR_TEST_ATTACHED (1 << 10) |
73 | #define SOR_TEST_HEAD_MODE_MASK (3 << 8) | 75 | #define SOR_TEST_HEAD_MODE_MASK (3 << 8) |
74 | #define SOR_TEST_HEAD_MODE_AWAKE (2 << 8) | 76 | #define SOR_TEST_HEAD_MODE_AWAKE (2 << 8) |
@@ -115,6 +117,8 @@ | |||
115 | 117 | ||
116 | #define SOR_LVDS 0x1c | 118 | #define SOR_LVDS 0x1c |
117 | #define SOR_CRC_A 0x1d | 119 | #define SOR_CRC_A 0x1d |
120 | #define SOR_CRC_A_VALID (1 << 0) | ||
121 | #define SOR_CRC_A_RESET (1 << 0) | ||
118 | #define SOR_CRC_B 0x1e | 122 | #define SOR_CRC_B 0x1e |
119 | #define SOR_BLANK 0x1f | 123 | #define SOR_BLANK 0x1f |
120 | #define SOR_SEQ_CTL 0x20 | 124 | #define SOR_SEQ_CTL 0x20 |