summaryrefslogtreecommitdiffstats
path: root/drivers/video/tegra/dc/dp.c
diff options
context:
space:
mode:
authorArun Kannan <akannan@nvidia.com>2017-05-12 20:03:36 -0400
committermobile promotions <svcmobile_promotions@nvidia.com>2017-05-23 22:29:38 -0400
commit5043bb4772042eb78e9ab744d5a37fd4c0d6319c (patch)
treed46dd4a2ddcf068d82378379893db4290fa00651 /drivers/video/tegra/dc/dp.c
parentf4835514cadb999aa1ba6f6a97847d8356e343ae (diff)
video: tegra: dp: Add debugfs to r/w DPCD reg
The debugfs directory is located here: /sys/kernel/debug/tegra_dp[n]/dpaux_dpcd The nodes available are: addr, num_bytes and data. User can read/write 'data' of size 'num_bytes' beginning at DPCD register offset specified in 'addr'. The format of data to be read/written is bytes separated by spaces. Each byte should be represented using 2 hexadecimal digits. Example read usage: cd /sys/kernel/debug/tegra_dp[n]/dpaux_dpcd echo 0x300 > addr echo 4 > num_bytes cat data 00 04 4b 00 Example write usage: cd /sys/kernel/debug/tegra_dp[n]/dpaux_dpcd echo 0x300 > addr echo 4 > num_bytes echo 00 04 4e 00 > data cat data 00 04 4e 00 Bug 1900877 Change-Id: I4186a133645f54cec3c866b731dae0a796aba2c2 Signed-off-by: Arun Kannan <akannan@nvidia.com> Reviewed-on: http://git-master/r/1481159 (cherry picked from commit 0fb6becd6b3100d727b63e8ef4544dbeaf7ecfac) Reviewed-on: http://git-master/r/1486072 Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com> Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
Diffstat (limited to 'drivers/video/tegra/dc/dp.c')
-rw-r--r--drivers/video/tegra/dc/dp.c196
1 files changed, 170 insertions, 26 deletions
diff --git a/drivers/video/tegra/dc/dp.c b/drivers/video/tegra/dc/dp.c
index 34309a440..c90c41f93 100644
--- a/drivers/video/tegra/dc/dp.c
+++ b/drivers/video/tegra/dc/dp.c
@@ -1097,55 +1097,92 @@ static const struct file_operations bits_per_pixel_fops = {
1097 .release = single_release, 1097 .release = single_release,
1098}; 1098};
1099 1099
1100static inline void dpaux_print_data(struct seq_file *s, u8 *data, u32 size)
1101{
1102 u8 row_size = 16;
1103 u32 i, j;
1104
1105 for (i = 0; i < size; i += row_size) {
1106 for (j = i; j < i + row_size && j < size; j++)
1107 seq_printf(s, "%02x ", data[j]);
1108 seq_puts(s, "\n");
1109 }
1110}
1111
1100static int dpaux_i2c_data_show(struct seq_file *s, void *unused) 1112static int dpaux_i2c_data_show(struct seq_file *s, void *unused)
1101{ 1113{
1102 struct tegra_dc_dp_data *dp = s->private; 1114 struct tegra_dc_dp_data *dp = s->private;
1103 u32 addr = dp->dpaux_i2c_dbg_addr; 1115 u32 addr = dp->dpaux_i2c_dbg_addr;
1104 u32 size = dp->dpaux_i2c_dbg_num_bytes; 1116 u32 size = dp->dpaux_i2c_dbg_num_bytes;
1105 u32 i, j, aux_stat; 1117 u32 aux_stat;
1106 u8 row_size = 16;
1107 u8 *data; 1118 u8 *data;
1119 int ret;
1108 1120
1109 data = kzalloc(size, GFP_KERNEL); 1121 data = kzalloc(size, GFP_KERNEL);
1110 if (!data) 1122 if (!data)
1111 return -ENOMEM; 1123 return -ENOMEM;
1112 1124
1113 tegra_dc_dp_i2c_read(dp, addr, data, &size, &aux_stat); 1125 ret = tegra_dc_dp_i2c_read(dp, addr, data, &size, &aux_stat);
1114 for (i = 0; i < size; i += row_size) { 1126 if (ret) {
1115 for (j = i; j < i + row_size && j < size; j++) 1127 seq_printf(s, "Error reading %d bytes from I2C reg %x",
1116 seq_printf(s, "%02x ", data[j]); 1128 dp->dpaux_i2c_dbg_num_bytes,
1117 seq_puts(s, "\n"); 1129 dp->dpaux_i2c_dbg_addr);
1130 goto free_mem;
1118 } 1131 }
1119 1132
1133 dpaux_print_data(s, data, size);
1134
1135free_mem:
1120 kfree(data); 1136 kfree(data);
1121 return 0; 1137 return ret;
1122} 1138}
1123 1139
1124static ssize_t dpaux_i2c_data_set(struct file *file, 1140static int dpaux_dpcd_data_show(struct seq_file *s, void *unused)
1125 const char __user *user_buf, size_t count, loff_t *off)
1126{ 1141{
1127 struct seq_file *s = file->private_data;
1128 struct tegra_dc_dp_data *dp = s->private; 1142 struct tegra_dc_dp_data *dp = s->private;
1129 u32 i = 0, size = 0; 1143 u32 addr = dp->dpaux_dpcd_dbg_addr;
1130 u32 aux_stat; 1144 u32 size = dp->dpaux_dpcd_dbg_num_bytes;
1131 u32 addr = dp->dpaux_i2c_dbg_addr; 1145 u32 i;
1132 u8 *data; 1146 u8 *data;
1147 int ret;
1148
1149 data = kzalloc(size, GFP_KERNEL);
1150 if (!data)
1151 return -ENOMEM;
1152
1153 for (i = 0; i < size; i++) {
1154 ret = tegra_dc_dp_dpcd_read(dp, addr+i, data+i);
1155 if (ret) {
1156 seq_printf(s, "Reading %d bytes from reg %x; "
1157 "Error at DPCD reg offset %x\n",
1158 dp->dpaux_dpcd_dbg_num_bytes,
1159 dp->dpaux_dpcd_dbg_addr,
1160 addr+i);
1161 goto free_mem;
1162 }
1163 }
1164
1165 dpaux_print_data(s, data, size);
1166
1167free_mem:
1168 kfree(data);
1169 return ret;
1170}
1171
1172static inline int dpaux_parse_input(const char __user *user_buf,
1173 u8 *data, size_t count)
1174{
1175 int size = 0;
1176 u32 i = 0;
1133 char tmp[3]; 1177 char tmp[3];
1134 char *buf; 1178 char *buf;
1135 int ret = count;
1136 1179
1137 buf = kzalloc(count, GFP_KERNEL); 1180 buf = kzalloc(count, GFP_KERNEL);
1138 if (!buf) 1181 if (!buf)
1139 return -ENOMEM; 1182 return -ENOMEM;
1140 1183
1141 data = kzalloc(count, GFP_KERNEL);
1142 if (!data) {
1143 ret = -ENOMEM;
1144 goto free_mem;
1145 }
1146
1147 if (copy_from_user(buf, user_buf, count)) { 1184 if (copy_from_user(buf, user_buf, count)) {
1148 ret = -EINVAL; 1185 size = -EINVAL;
1149 goto free_mem; 1186 goto free_mem;
1150 } 1187 }
1151 1188
@@ -1155,14 +1192,14 @@ static ssize_t dpaux_i2c_data_set(struct file *file,
1155 * amount of whitespace between each XX. 1192 * amount of whitespace between each XX.
1156 */ 1193 */
1157 while (i + 1 < count) { 1194 while (i + 1 < count) {
1158 if (isspace(buf[i])) { 1195 if (buf[i] == ' ') {
1159 i += 1; 1196 i += 1;
1160 continue; 1197 continue;
1161 } 1198 }
1162 1199
1163 tmp[0] = buf[i]; tmp[1] = buf[i + 1]; tmp[2] = '\0'; 1200 tmp[0] = buf[i]; tmp[1] = buf[i + 1]; tmp[2] = '\0';
1164 if (kstrtou8(tmp, 16, data + size)) { 1201 if (kstrtou8(tmp, 16, data + size)) {
1165 ret = -EINVAL; 1202 size = -EINVAL;
1166 goto free_mem; 1203 goto free_mem;
1167 } 1204 }
1168 1205
@@ -1170,10 +1207,73 @@ static ssize_t dpaux_i2c_data_set(struct file *file,
1170 i += 2; 1207 i += 2;
1171 } 1208 }
1172 1209
1173 tegra_dc_dp_i2c_write(dp, addr, data, &size, &aux_stat);
1174
1175free_mem: 1210free_mem:
1176 kfree(buf); 1211 kfree(buf);
1212 return size;
1213}
1214
1215static ssize_t dpaux_i2c_data_set(struct file *file,
1216 const char __user *user_buf, size_t count, loff_t *off)
1217{
1218 struct seq_file *s = file->private_data;
1219 struct tegra_dc_dp_data *dp = s->private;
1220 int size = 0;
1221 u32 aux_stat;
1222 u32 addr = dp->dpaux_i2c_dbg_addr;
1223 u8 *data;
1224 int ret = count;
1225
1226 data = kzalloc(count, GFP_KERNEL);
1227 if (!data)
1228 return -ENOMEM;
1229
1230 size = dpaux_parse_input(user_buf, data, count);
1231 if (size <= 0) {
1232 ret = -EINVAL;
1233 goto free_mem;
1234 }
1235
1236 ret = tegra_dc_dp_i2c_write(dp, addr, data, &size, &aux_stat);
1237 if (!ret)
1238 ret = count;
1239 else
1240 ret = -EIO;
1241
1242free_mem:
1243 kfree(data);
1244
1245 return ret;
1246}
1247
1248static ssize_t dpaux_dpcd_data_set(struct file *file,
1249 const char __user *user_buf, size_t count, loff_t *off)
1250{
1251 struct seq_file *s = file->private_data;
1252 struct tegra_dc_dp_data *dp = s->private;
1253 int size = 0;
1254 u32 aux_stat;
1255 u32 addr = dp->dpaux_dpcd_dbg_addr;
1256 u8 *data;
1257 int ret = count;
1258
1259 data = kzalloc(count, GFP_KERNEL);
1260 if (!data)
1261 return -ENOMEM;
1262
1263 size = dpaux_parse_input(user_buf, data, count);
1264 if (size <= 0) {
1265 ret = -EINVAL;
1266 goto free_mem;
1267 }
1268
1269 ret = tegra_dc_dpaux_write(dp, DPAUX_DP_AUXCTL_CMD_AUXWR,
1270 addr, data, &size, &aux_stat);
1271 if (!ret)
1272 ret = count;
1273 else
1274 ret = -EIO;
1275
1276free_mem:
1177 kfree(data); 1277 kfree(data);
1178 1278
1179 return ret; 1279 return ret;
@@ -1184,6 +1284,11 @@ static int dpaux_i2c_data_open(struct inode *inode, struct file *file)
1184 return single_open(file, dpaux_i2c_data_show, inode->i_private); 1284 return single_open(file, dpaux_i2c_data_show, inode->i_private);
1185} 1285}
1186 1286
1287static int dpaux_dpcd_data_open(struct inode *inode, struct file *file)
1288{
1289 return single_open(file, dpaux_dpcd_data_show, inode->i_private);
1290}
1291
1187static const struct file_operations dpaux_i2c_data_fops = { 1292static const struct file_operations dpaux_i2c_data_fops = {
1188 .open = dpaux_i2c_data_open, 1293 .open = dpaux_i2c_data_open,
1189 .read = seq_read, 1294 .read = seq_read,
@@ -1192,6 +1297,14 @@ static const struct file_operations dpaux_i2c_data_fops = {
1192 .release = single_release, 1297 .release = single_release,
1193}; 1298};
1194 1299
1300static const struct file_operations dpaux_dpcd_data_fops = {
1301 .open = dpaux_dpcd_data_open,
1302 .read = seq_read,
1303 .write = dpaux_dpcd_data_set,
1304 .llseek = seq_lseek,
1305 .release = single_release,
1306};
1307
1195static struct dentry *tegra_dpaux_i2c_dir_create(struct tegra_dc_dp_data *dp, 1308static struct dentry *tegra_dpaux_i2c_dir_create(struct tegra_dc_dp_data *dp,
1196 struct dentry *parent) 1309 struct dentry *parent)
1197{ 1310{
@@ -1220,6 +1333,34 @@ free_out:
1220 return retval; 1333 return retval;
1221} 1334}
1222 1335
1336static struct dentry *tegra_dpaux_dpcd_dir_create(struct tegra_dc_dp_data *dp,
1337 struct dentry *parent)
1338{
1339 struct dentry *dpaux_dir;
1340 struct dentry *retval = NULL;
1341
1342 dpaux_dir = debugfs_create_dir("dpaux_dpcd", parent);
1343 if (!dpaux_dir)
1344 return retval;
1345 retval = debugfs_create_u16("addr", S_IRUGO | S_IWUGO, dpaux_dir,
1346 &dp->dpaux_dpcd_dbg_addr);
1347 if (!retval)
1348 goto free_out;
1349 retval = debugfs_create_u32("num_bytes", S_IRUGO | S_IWUGO,
1350 dpaux_dir, &dp->dpaux_dpcd_dbg_num_bytes);
1351 if (!retval)
1352 goto free_out;
1353 retval = debugfs_create_file("data", S_IRUGO, dpaux_dir, dp,
1354 &dpaux_dpcd_data_fops);
1355 if (!retval)
1356 goto free_out;
1357
1358 return retval;
1359free_out:
1360 debugfs_remove_recursive(dpaux_dir);
1361 return retval;
1362}
1363
1223static void tegra_dc_dp_debugfs_create(struct tegra_dc_dp_data *dp) 1364static void tegra_dc_dp_debugfs_create(struct tegra_dc_dp_data *dp)
1224{ 1365{
1225 struct dentry *retval; 1366 struct dentry *retval;
@@ -1257,6 +1398,9 @@ static void tegra_dc_dp_debugfs_create(struct tegra_dc_dp_data *dp)
1257 retval = tegra_dpaux_i2c_dir_create(dp, dp->debugdir); 1398 retval = tegra_dpaux_i2c_dir_create(dp, dp->debugdir);
1258 if (!retval) 1399 if (!retval)
1259 goto free_out; 1400 goto free_out;
1401 retval = tegra_dpaux_dpcd_dir_create(dp, dp->debugdir);
1402 if (!retval)
1403 goto free_out;
1260 1404
1261 /* hotplug not allowed for eDP */ 1405 /* hotplug not allowed for eDP */
1262 if (is_hotplug_supported(dp)) { 1406 if (is_hotplug_supported(dp)) {