xref: /linux/drivers/gpu/drm/i915/display/intel_display_debugfs_params.c (revision 2c1ed907520c50326b8f604907a8478b27881a2e)
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright © 2023 Intel Corporation
4  */
5 
6 #include <linux/debugfs.h>
7 #include <linux/kernel.h>
8 
9 #include <drm/drm_drv.h>
10 #include <drm/drm_file.h>
11 
12 #include "intel_display_core.h"
13 #include "intel_display_debugfs_params.h"
14 #include "intel_display_params.h"
15 
16 /* int param */
intel_display_param_int_show(struct seq_file * m,void * data)17 static int intel_display_param_int_show(struct seq_file *m, void *data)
18 {
19 	int *value = m->private;
20 
21 	seq_printf(m, "%d\n", *value);
22 
23 	return 0;
24 }
25 
intel_display_param_int_open(struct inode * inode,struct file * file)26 static int intel_display_param_int_open(struct inode *inode, struct file *file)
27 {
28 	return single_open(file, intel_display_param_int_show, inode->i_private);
29 }
30 
intel_display_param_int_write(struct file * file,const char __user * ubuf,size_t len,loff_t * offp)31 static ssize_t intel_display_param_int_write(struct file *file,
32 					     const char __user *ubuf, size_t len,
33 					     loff_t *offp)
34 {
35 	struct seq_file *m = file->private_data;
36 	int *value = m->private;
37 	int ret;
38 
39 	ret = kstrtoint_from_user(ubuf, len, 0, value);
40 	if (ret) {
41 		/* support boolean values too */
42 		bool b;
43 
44 		ret = kstrtobool_from_user(ubuf, len, &b);
45 		if (!ret)
46 			*value = b;
47 	}
48 
49 	return ret ?: len;
50 }
51 
52 static const struct file_operations intel_display_param_int_fops = {
53 	.owner = THIS_MODULE,
54 	.open = intel_display_param_int_open,
55 	.read = seq_read,
56 	.write = intel_display_param_int_write,
57 	.llseek = default_llseek,
58 	.release = single_release,
59 };
60 
61 static const struct file_operations intel_display_param_int_fops_ro = {
62 	.owner = THIS_MODULE,
63 	.open = intel_display_param_int_open,
64 	.read = seq_read,
65 	.llseek = default_llseek,
66 	.release = single_release,
67 };
68 
69 /* unsigned int param */
intel_display_param_uint_show(struct seq_file * m,void * data)70 static int intel_display_param_uint_show(struct seq_file *m, void *data)
71 {
72 	unsigned int *value = m->private;
73 
74 	seq_printf(m, "%u\n", *value);
75 
76 	return 0;
77 }
78 
intel_display_param_uint_open(struct inode * inode,struct file * file)79 static int intel_display_param_uint_open(struct inode *inode, struct file *file)
80 {
81 	return single_open(file, intel_display_param_uint_show, inode->i_private);
82 }
83 
intel_display_param_uint_write(struct file * file,const char __user * ubuf,size_t len,loff_t * offp)84 static ssize_t intel_display_param_uint_write(struct file *file,
85 					      const char __user *ubuf, size_t len,
86 					      loff_t *offp)
87 {
88 	struct seq_file *m = file->private_data;
89 	unsigned int *value = m->private;
90 	int ret;
91 
92 	ret = kstrtouint_from_user(ubuf, len, 0, value);
93 	if (ret) {
94 		/* support boolean values too */
95 		bool b;
96 
97 		ret = kstrtobool_from_user(ubuf, len, &b);
98 		if (!ret)
99 			*value = b;
100 	}
101 
102 	return ret ?: len;
103 }
104 
105 static const struct file_operations intel_display_param_uint_fops = {
106 	.owner = THIS_MODULE,
107 	.open = intel_display_param_uint_open,
108 	.read = seq_read,
109 	.write = intel_display_param_uint_write,
110 	.llseek = default_llseek,
111 	.release = single_release,
112 };
113 
114 static const struct file_operations intel_display_param_uint_fops_ro = {
115 	.owner = THIS_MODULE,
116 	.open = intel_display_param_uint_open,
117 	.read = seq_read,
118 	.llseek = default_llseek,
119 	.release = single_release,
120 };
121 
122 #define RO(mode) (((mode) & 0222) == 0)
123 
124 __maybe_unused static struct dentry *
intel_display_debugfs_create_int(const char * name,umode_t mode,struct dentry * parent,int * value)125 intel_display_debugfs_create_int(const char *name, umode_t mode,
126 			struct dentry *parent, int *value)
127 {
128 	return debugfs_create_file_unsafe(name, mode, parent, value,
129 					  RO(mode) ? &intel_display_param_int_fops_ro :
130 					  &intel_display_param_int_fops);
131 }
132 
133 __maybe_unused static struct dentry *
intel_display_debugfs_create_uint(const char * name,umode_t mode,struct dentry * parent,unsigned int * value)134 intel_display_debugfs_create_uint(const char *name, umode_t mode,
135 			 struct dentry *parent, unsigned int *value)
136 {
137 	return debugfs_create_file_unsafe(name, mode, parent, value,
138 					  RO(mode) ? &intel_display_param_uint_fops_ro :
139 					  &intel_display_param_uint_fops);
140 }
141 
142 #define _intel_display_param_create_file(parent, name, mode, valp)	\
143 	do {								\
144 		if (mode)						\
145 			_Generic(valp,					\
146 				 bool * : debugfs_create_bool,		\
147 				 int * : intel_display_debugfs_create_int, \
148 				 unsigned int * : intel_display_debugfs_create_uint, \
149 				 unsigned long * : debugfs_create_ulong, \
150 				 char ** : debugfs_create_str) \
151 				(name, mode, parent, valp);		\
152 	} while (0)
153 
154 /* add a subdirectory with files for each intel display param */
intel_display_debugfs_params(struct intel_display * display)155 void intel_display_debugfs_params(struct intel_display *display)
156 {
157 	struct drm_minor *minor = display->drm->primary;
158 	struct dentry *dir;
159 	char dirname[16];
160 
161 	snprintf(dirname, sizeof(dirname), "%s_params", display->drm->driver->name);
162 	dir = debugfs_lookup(dirname, minor->debugfs_root);
163 	if (!dir)
164 		dir = debugfs_create_dir(dirname, minor->debugfs_root);
165 	if (IS_ERR(dir))
166 		return;
167 
168 	/*
169 	 * Note: We could create files for params needing special handling
170 	 * here. Set mode in params to 0 to skip the generic create file, or
171 	 * just let the generic create file fail silently with -EEXIST.
172 	 */
173 
174 #define REGISTER(T, x, unused, mode, ...) _intel_display_param_create_file( \
175 		dir, #x, mode, &display->params.x);
176 	INTEL_DISPLAY_PARAMS_FOR_EACH(REGISTER);
177 #undef REGISTER
178 }
179