1169689Skan// SPDX-License-Identifier: MIT 2169689Skan/* 3169689Skan * Copyright �� 2023 Intel Corporation 4169689Skan */ 5169689Skan 6169689Skan#include <linux/debugfs.h> 7169689Skan#include <linux/kernel.h> 8169689Skan 9169689Skan#include <drm/drm_drv.h> 10169689Skan 11169689Skan#include "intel_display_debugfs_params.h" 12169689Skan#include "i915_drv.h" 13169689Skan#include "intel_display_params.h" 14169689Skan 15169689Skan/* int param */ 16169689Skanstatic int intel_display_param_int_show(struct seq_file *m, void *data) 17169689Skan{ 18169689Skan int *value = m->private; 19169689Skan 20169689Skan seq_printf(m, "%d\n", *value); 21169689Skan 22169689Skan return 0; 23169689Skan} 24169689Skan 25169689Skanstatic int intel_display_param_int_open(struct inode *inode, struct file *file) 26169689Skan{ 27169689Skan return single_open(file, intel_display_param_int_show, inode->i_private); 28169689Skan} 29169689Skan 30169689Skanstatic ssize_t intel_display_param_int_write(struct file *file, 31169689Skan const char __user *ubuf, size_t len, 32169689Skan loff_t *offp) 33169689Skan{ 34169689Skan struct seq_file *m = file->private_data; 35169689Skan int *value = m->private; 36169689Skan int ret; 37169689Skan 38169689Skan ret = kstrtoint_from_user(ubuf, len, 0, value); 39169689Skan if (ret) { 40169689Skan /* support boolean values too */ 41169689Skan bool b; 42169689Skan 43169689Skan ret = kstrtobool_from_user(ubuf, len, &b); 44169689Skan if (!ret) 45169689Skan *value = b; 46169689Skan } 47169689Skan 48169689Skan return ret ?: len; 49169689Skan} 50169689Skan 51169689Skanstatic const struct file_operations intel_display_param_int_fops = { 52169689Skan .owner = THIS_MODULE, 53169689Skan .open = intel_display_param_int_open, 54169689Skan .read = seq_read, 55169689Skan .write = intel_display_param_int_write, 56169689Skan .llseek = default_llseek, 57169689Skan .release = single_release, 58169689Skan}; 59169689Skan 60169689Skanstatic const struct file_operations intel_display_param_int_fops_ro = { 61169689Skan .owner = THIS_MODULE, 62169689Skan .open = intel_display_param_int_open, 63169689Skan .read = seq_read, 64169689Skan .llseek = default_llseek, 65169689Skan .release = single_release, 66169689Skan}; 67169689Skan 68169689Skan/* unsigned int param */ 69169689Skanstatic int intel_display_param_uint_show(struct seq_file *m, void *data) 70169689Skan{ 71169689Skan unsigned int *value = m->private; 72169689Skan 73169689Skan seq_printf(m, "%u\n", *value); 74169689Skan 75169689Skan return 0; 76169689Skan} 77169689Skan 78169689Skanstatic int intel_display_param_uint_open(struct inode *inode, struct file *file) 79169689Skan{ 80 return single_open(file, intel_display_param_uint_show, inode->i_private); 81} 82 83static ssize_t intel_display_param_uint_write(struct file *file, 84 const char __user *ubuf, size_t len, 85 loff_t *offp) 86{ 87 struct seq_file *m = file->private_data; 88 unsigned int *value = m->private; 89 int ret; 90 91 ret = kstrtouint_from_user(ubuf, len, 0, value); 92 if (ret) { 93 /* support boolean values too */ 94 bool b; 95 96 ret = kstrtobool_from_user(ubuf, len, &b); 97 if (!ret) 98 *value = b; 99 } 100 101 return ret ?: len; 102} 103 104static const struct file_operations intel_display_param_uint_fops = { 105 .owner = THIS_MODULE, 106 .open = intel_display_param_uint_open, 107 .read = seq_read, 108 .write = intel_display_param_uint_write, 109 .llseek = default_llseek, 110 .release = single_release, 111}; 112 113static const struct file_operations intel_display_param_uint_fops_ro = { 114 .owner = THIS_MODULE, 115 .open = intel_display_param_uint_open, 116 .read = seq_read, 117 .llseek = default_llseek, 118 .release = single_release, 119}; 120 121#define RO(mode) (((mode) & 0222) == 0) 122 123__maybe_unused static struct dentry * 124intel_display_debugfs_create_int(const char *name, umode_t mode, 125 struct dentry *parent, int *value) 126{ 127 return debugfs_create_file_unsafe(name, mode, parent, value, 128 RO(mode) ? &intel_display_param_int_fops_ro : 129 &intel_display_param_int_fops); 130} 131 132__maybe_unused static struct dentry * 133intel_display_debugfs_create_uint(const char *name, umode_t mode, 134 struct dentry *parent, unsigned int *value) 135{ 136 return debugfs_create_file_unsafe(name, mode, parent, value, 137 RO(mode) ? &intel_display_param_uint_fops_ro : 138 &intel_display_param_uint_fops); 139} 140 141#define _intel_display_param_create_file(parent, name, mode, valp) \ 142 do { \ 143 if (mode) \ 144 _Generic(valp, \ 145 bool * : debugfs_create_bool, \ 146 int * : intel_display_debugfs_create_int, \ 147 unsigned int * : intel_display_debugfs_create_uint, \ 148 unsigned long * : debugfs_create_ulong, \ 149 char ** : debugfs_create_str) \ 150 (name, mode, parent, valp); \ 151 } while (0) 152 153/* add a subdirectory with files for each intel display param */ 154void intel_display_debugfs_params(struct drm_i915_private *i915) 155{ 156 struct drm_minor *minor = i915->drm.primary; 157 struct dentry *dir; 158 char dirname[16]; 159 160 snprintf(dirname, sizeof(dirname), "%s_params", i915->drm.driver->name); 161 dir = debugfs_lookup(dirname, minor->debugfs_root); 162 if (!dir) 163 dir = debugfs_create_dir(dirname, minor->debugfs_root); 164 if (IS_ERR(dir)) 165 return; 166 167 /* 168 * Note: We could create files for params needing special handling 169 * here. Set mode in params to 0 to skip the generic create file, or 170 * just let the generic create file fail silently with -EEXIST. 171 */ 172 173#define REGISTER(T, x, unused, mode, ...) _intel_display_param_create_file( \ 174 dir, #x, mode, &i915->display.params.x); 175 INTEL_DISPLAY_PARAMS_FOR_EACH(REGISTER); 176#undef REGISTER 177} 178