summaryrefslogtreecommitdiff
path: root/drivers/misc
diff options
context:
space:
mode:
authorLael Jones <lajones@nvidia.com>2014-03-14 09:43:56 -0700
committerBo Yan <byan@nvidia.com>2014-03-25 14:03:37 -0700
commitded1580ceca63d5923c83b42324bbc07c1ede5e1 (patch)
tree71207bf6aecf879781d24c60bf2b4632e15291fc /drivers/misc
parent7521a15df5f63c8b41b9f7e6896d751ea8e7a33f (diff)
misc: mods: Add MODS debugfs interface
Add export of Tegra DC driver features through the MODS debugfs interface Signed-off-by: Lael Jones <lajones@nvidia.com> Change-Id: Ibc3b3a031aca1339fd9b02db816a38b4c32d6730 Reviewed-on: http://git-master/r/382091 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Jon Mayo <jmayo@nvidia.com> Reviewed-by: Dan Merget <dmerget@nvidia.com> Reviewed-by: Chris Dragan <kdragan@nvidia.com> Tested-by: Chris Dragan <kdragan@nvidia.com> Reviewed-by: Bo Yan <byan@nvidia.com> Tested-by: Bo Yan <byan@nvidia.com>
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/mods/Makefile1
-rw-r--r--drivers/misc/mods/mods_debugfs.c345
-rw-r--r--drivers/misc/mods/mods_internal.h12
-rw-r--r--drivers/misc/mods/mods_krnl.c7
4 files changed, 365 insertions, 0 deletions
diff --git a/drivers/misc/mods/Makefile b/drivers/misc/mods/Makefile
index 986d2d142f82..0880c2509e1f 100644
--- a/drivers/misc/mods/Makefile
+++ b/drivers/misc/mods/Makefile
@@ -5,3 +5,4 @@ mods-y += mods_irq.o
mods-$(CONFIG_PCI) += mods_pci.o
mods-$(CONFIG_ACPI) += mods_acpi.o
mods-$(CONFIG_ARCH_TEGRA) += mods_clock.o
+mods-$(CONFIG_DEBUG_FS) += mods_debugfs.o
diff --git a/drivers/misc/mods/mods_debugfs.c b/drivers/misc/mods/mods_debugfs.c
new file mode 100644
index 000000000000..942030224f41
--- /dev/null
+++ b/drivers/misc/mods/mods_debugfs.c
@@ -0,0 +1,345 @@
+/*
+ * mods_debugfs.c - This file is part of NVIDIA MODS kernel driver.
+ *
+ * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA MODS kernel driver is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * NVIDIA MODS kernel driver is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with NVIDIA MODS kernel driver.
+ * If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+#ifdef CONFIG_TEGRA_DC
+#include <../drivers/video/tegra/dc/dc_config.h>
+#endif
+
+static struct dentry *mods_debugfs_dir;
+
+#ifdef CONFIG_TEGRA_DC
+static int mods_dc_color_formats_show(struct seq_file *s, void *unused)
+{
+ struct tegra_dc *dc = s->private;
+ u32 i, j;
+
+ for (i = 0; i < DC_N_WINDOWS; i++) {
+ struct tegra_dc_win *win;
+ u32 *fmt_masks;
+ win = tegra_dc_get_window(dc, i);
+ if (!win)
+ continue;
+ fmt_masks = tegra_dc_parse_feature(dc, i, GET_WIN_FORMATS);
+ if (!fmt_masks)
+ continue;
+ seq_printf(s, "window_%u:", i);
+ for (j = 0; j < ENTRY_SIZE; j++)
+ seq_printf(s, " 0x%08x", fmt_masks[j]);
+ seq_puts(s, "\n");
+ }
+ return 0;
+}
+
+static int mods_dc_color_formats_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, mods_dc_color_formats_show, inode->i_private);
+}
+
+static const struct file_operations mods_dc_color_formats_fops = {
+ .open = mods_dc_color_formats_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int mods_dc_blend_gen_show(struct seq_file *s, void *unused)
+{
+ struct tegra_dc *dc = s->private;
+ u32 i;
+
+ for (i = 0; i < DC_N_WINDOWS; i++) {
+ struct tegra_dc_win *win;
+ u32 *blend_gen;
+ win = tegra_dc_get_window(dc, i);
+ if (!win)
+ continue;
+ blend_gen = tegra_dc_parse_feature(dc, i, HAS_GEN2_BLEND);
+ if (!blend_gen)
+ continue;
+ seq_printf(s, "window_%u: %u\n", i,
+ blend_gen[BLEND_GENERATION]);
+ }
+ return 0;
+}
+
+static int mods_dc_blend_gen_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, mods_dc_blend_gen_show, inode->i_private);
+}
+
+static const struct file_operations mods_dc_blend_gen_fops = {
+ .open = mods_dc_blend_gen_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int mods_dc_layout_show(struct seq_file *s, void *unused)
+{
+ struct tegra_dc *dc = s->private;
+ u32 i;
+
+ seq_puts(s, " Pitch Tiled Block\n");
+ for (i = 0; i < DC_N_WINDOWS; i++) {
+ struct tegra_dc_win *win;
+ u32 *layouts;
+ win = tegra_dc_get_window(dc, i);
+ if (!win)
+ continue;
+ layouts = tegra_dc_parse_feature(dc, i, HAS_TILED);
+ if (!layouts)
+ continue;
+ seq_printf(s, "window_%u: %5u %5u %5u\n", i,
+ layouts[PITCHED_LAYOUT],
+ layouts[TILED_LAYOUT],
+ layouts[BLOCK_LINEAR]);
+ }
+ return 0;
+}
+
+static int mods_dc_layout_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, mods_dc_layout_show, inode->i_private);
+}
+
+static const struct file_operations mods_dc_layout_fops = {
+ .open = mods_dc_layout_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int mods_dc_invert_show(struct seq_file *s, void *unused)
+{
+ struct tegra_dc *dc = s->private;
+ u32 i;
+
+ seq_puts(s, " FlipH FlipV ScanColumn\n");
+ for (i = 0; i < DC_N_WINDOWS; i++) {
+ struct tegra_dc_win *win;
+ u32 *invert_data;
+ win = tegra_dc_get_window(dc, i);
+ if (!win)
+ continue;
+ invert_data = tegra_dc_parse_feature(dc, i, GET_INVERT);
+ if (!invert_data)
+ continue;
+ seq_printf(s, "window_%u: %5u %5u %10u\n", i,
+ invert_data[H_INVERT],
+ invert_data[V_INVERT],
+ invert_data[SCAN_COLUMN]);
+ }
+ return 0;
+}
+
+static int mods_dc_invert_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, mods_dc_invert_show, inode->i_private);
+}
+
+static const struct file_operations mods_dc_invert_fops = {
+ .open = mods_dc_invert_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int mods_dc_interlaced_show(struct seq_file *s, void *unused)
+{
+ struct tegra_dc *dc = s->private;
+ u32 i;
+#ifdef CONFIG_TEGRA_DC_INTERLACE
+ const unsigned head_interlaced = 1;
+#else
+ const unsigned head_interlaced = 0;
+#endif
+
+ seq_printf(s, "head: %u\n", head_interlaced);
+ for (i = 0; i < DC_N_WINDOWS; i++) {
+ struct tegra_dc_win *win;
+ u32 *interlaced;
+ win = tegra_dc_get_window(dc, i);
+ if (!win)
+ continue;
+ interlaced = tegra_dc_parse_feature(dc, i, HAS_INTERLACE);
+ if (!interlaced)
+ continue;
+ seq_printf(s, "window_%u: %u\n", i, interlaced[0]);
+ }
+ return 0;
+}
+
+static int mods_dc_interlaced_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, mods_dc_interlaced_show, inode->i_private);
+}
+
+static const struct file_operations mods_dc_interlaced_fops = {
+ .open = mods_dc_interlaced_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int mods_dc_window_mask_show(struct seq_file *s, void *unused)
+{
+ struct tegra_dc *dc = s->private;
+ seq_printf(s, "0x%02lx\n", dc->valid_windows);
+ return 0;
+}
+
+static int mods_dc_window_mask_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, mods_dc_window_mask_show, inode->i_private);
+}
+
+static const struct file_operations mods_dc_window_mask_fops = {
+ .open = mods_dc_window_mask_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int mods_dc_scaling_show(struct seq_file *s, void *unused)
+{
+ struct tegra_dc *dc = s->private;
+ u32 i;
+
+ seq_puts(s, " UpH UpV DownH DownV\n");
+ for (i = 0; i < DC_N_WINDOWS; i++) {
+ struct tegra_dc_win *win;
+ u32 *scaling;
+ win = tegra_dc_get_window(dc, i);
+ if (!win)
+ continue;
+ scaling = tegra_dc_parse_feature(dc, i, HAS_SCALE);
+ if (!scaling)
+ continue;
+ seq_printf(s, "window_%u: %3u %3u %5u %5u\n", i,
+ scaling[H_SCALE_UP],
+ scaling[V_SCALE_UP],
+ scaling[H_FILTER_DOWN],
+ scaling[V_FILTER_DOWN]);
+ }
+ return 0;
+}
+
+static int mods_dc_scaling_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, mods_dc_scaling_show, inode->i_private);
+}
+
+static const struct file_operations mods_dc_scaling_fops = {
+ .open = mods_dc_scaling_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+#endif
+
+void mods_remove_debugfs(void)
+{
+ debugfs_remove_recursive(mods_debugfs_dir);
+ mods_debugfs_dir = NULL;
+}
+
+int mods_create_debugfs(struct miscdevice *modsdev)
+{
+ struct dentry *retval;
+#ifdef CONFIG_TEGRA_DC
+ unsigned dc_idx;
+#endif
+ int err = 0;
+
+ mods_debugfs_dir = debugfs_create_dir(dev_name(modsdev->this_device),
+ NULL);
+ if (IS_ERR(mods_debugfs_dir)) {
+ err = -EIO;
+ goto remove_out;
+ }
+
+#ifdef CONFIG_TEGRA_DC
+ for (dc_idx = 0; dc_idx < TEGRA_MAX_DC; dc_idx++) {
+ struct dentry *dc_debugfs_dir;
+ struct tegra_dc *dc = tegra_dc_get_dc(dc_idx);
+ if (!dc)
+ continue;
+
+ dc_debugfs_dir = debugfs_create_dir(dev_name(&dc->ndev->dev),
+ mods_debugfs_dir);
+ if (IS_ERR(dc_debugfs_dir)) {
+ err = -EIO;
+ goto remove_out;
+ }
+
+ retval = debugfs_create_file("window_mask", S_IRUGO,
+ dc_debugfs_dir, dc, &mods_dc_window_mask_fops);
+ if (IS_ERR(retval)) {
+ err = -EIO;
+ goto remove_out;
+ }
+ retval = debugfs_create_file("color_formats", S_IRUGO,
+ dc_debugfs_dir, dc, &mods_dc_color_formats_fops);
+ if (IS_ERR(retval)) {
+ err = -EIO;
+ goto remove_out;
+ }
+ retval = debugfs_create_file("blend_gen", S_IRUGO,
+ dc_debugfs_dir, dc, &mods_dc_blend_gen_fops);
+ if (IS_ERR(retval)) {
+ err = -EIO;
+ goto remove_out;
+ }
+ retval = debugfs_create_file("layout", S_IRUGO, dc_debugfs_dir,
+ dc, &mods_dc_layout_fops);
+ if (IS_ERR(retval)) {
+ err = -EIO;
+ goto remove_out;
+ }
+ retval = debugfs_create_file("invert", S_IRUGO, dc_debugfs_dir,
+ dc, &mods_dc_invert_fops);
+ if (IS_ERR(retval)) {
+ err = -EIO;
+ goto remove_out;
+ }
+ retval = debugfs_create_file("interlaced", S_IRUGO,
+ dc_debugfs_dir, dc, &mods_dc_interlaced_fops);
+ if (IS_ERR(retval)) {
+ err = -EIO;
+ goto remove_out;
+ }
+ retval = debugfs_create_file("scaling", S_IRUGO, dc_debugfs_dir,
+ dc, &mods_dc_scaling_fops);
+ if (IS_ERR(retval)) {
+ err = -EIO;
+ goto remove_out;
+ }
+ }
+#endif
+
+ return 0;
+remove_out:
+ dev_err(modsdev->this_device, "could not create debugfs\n");
+ mods_remove_debugfs();
+ return err;
+}
+
diff --git a/drivers/misc/mods/mods_internal.h b/drivers/misc/mods/mods_internal.h
index 2e24db672b85..0b64717c767e 100644
--- a/drivers/misc/mods/mods_internal.h
+++ b/drivers/misc/mods/mods_internal.h
@@ -24,6 +24,7 @@
#include <linux/list.h>
#include <linux/pci.h>
#include <linux/slab.h>
+#include <linux/miscdevice.h>
#define NvU8 u8
#define NvU16 u16
@@ -443,4 +444,15 @@ int esc_mods_flush_cpu_cache_range(struct file *,
struct MODS_FLUSH_CPU_CACHE_RANGE *);
#endif
+#ifdef CONFIG_DEBUG_FS
+int mods_create_debugfs(struct miscdevice *modsdev);
+void mods_remove_debugfs(void);
+#else
+static inline int mods_create_debugfs(struct miscdevice *modsdev)
+{
+ return 0;
+}
+static inline void mods_remove_debugfs(void) {}
+#endif /* CONFIG_DEBUG_FS */
+
#endif /* _MODS_INTERNAL_H_ */
diff --git a/drivers/misc/mods/mods_krnl.c b/drivers/misc/mods/mods_krnl.c
index f1ac5c695cf9..b17a4f278d00 100644
--- a/drivers/misc/mods/mods_krnl.c
+++ b/drivers/misc/mods/mods_krnl.c
@@ -94,6 +94,10 @@ static int __init mods_init_module(void)
mods_init_clock_api();
#endif
+ rc = mods_create_debugfs(&mods_dev);
+ if (rc < 0)
+ return rc;
+
mods_info_printk("driver loaded, version %x.%02x\n",
(MODS_DRIVER_VERSION>>8),
(MODS_DRIVER_VERSION&0xFF));
@@ -104,6 +108,9 @@ static int __init mods_init_module(void)
static void __exit mods_exit_module(void)
{
LOG_ENT();
+
+ mods_remove_debugfs();
+
mods_cleanup_irq();
misc_deregister(&mods_dev);