linux/drivers/gpu/drm/msm/dp/dp_debug.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
   4 */
   5
   6#define pr_fmt(fmt)"[drm-dp] %s: " fmt, __func__
   7
   8#include <linux/debugfs.h>
   9#include <drm/drm_connector.h>
  10#include <drm/drm_file.h>
  11
  12#include "dp_parser.h"
  13#include "dp_catalog.h"
  14#include "dp_aux.h"
  15#include "dp_ctrl.h"
  16#include "dp_debug.h"
  17#include "dp_display.h"
  18
  19#define DEBUG_NAME "msm_dp"
  20
  21struct dp_debug_private {
  22        struct dentry *root;
  23
  24        struct dp_usbpd *usbpd;
  25        struct dp_link *link;
  26        struct dp_panel *panel;
  27        struct drm_connector **connector;
  28        struct device *dev;
  29        struct drm_device *drm_dev;
  30
  31        struct dp_debug dp_debug;
  32};
  33
  34static int dp_debug_check_buffer_overflow(int rc, int *max_size, int *len)
  35{
  36        if (rc >= *max_size) {
  37                DRM_ERROR("buffer overflow\n");
  38                return -EINVAL;
  39        }
  40        *len += rc;
  41        *max_size = SZ_4K - *len;
  42
  43        return 0;
  44}
  45
  46static ssize_t dp_debug_read_info(struct file *file, char __user *user_buff,
  47                size_t count, loff_t *ppos)
  48{
  49        struct dp_debug_private *debug = file->private_data;
  50        char *buf;
  51        u32 len = 0, rc = 0;
  52        u64 lclk = 0;
  53        u32 max_size = SZ_4K;
  54        u32 link_params_rate;
  55        struct drm_display_mode *drm_mode;
  56
  57        if (!debug)
  58                return -ENODEV;
  59
  60        if (*ppos)
  61                return 0;
  62
  63        buf = kzalloc(SZ_4K, GFP_KERNEL);
  64        if (!buf)
  65                return -ENOMEM;
  66
  67        drm_mode = &debug->panel->dp_mode.drm_mode;
  68
  69        rc = snprintf(buf + len, max_size, "\tname = %s\n", DEBUG_NAME);
  70        if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
  71                goto error;
  72
  73        rc = snprintf(buf + len, max_size,
  74                        "\tdp_panel\n\t\tmax_pclk_khz = %d\n",
  75                        debug->panel->max_pclk_khz);
  76        if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
  77                goto error;
  78
  79        rc = snprintf(buf + len, max_size,
  80                        "\tdrm_dp_link\n\t\trate = %u\n",
  81                        debug->panel->link_info.rate);
  82        if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
  83                goto error;
  84
  85        rc = snprintf(buf + len, max_size,
  86                         "\t\tnum_lanes = %u\n",
  87                        debug->panel->link_info.num_lanes);
  88        if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
  89                goto error;
  90
  91        rc = snprintf(buf + len, max_size,
  92                        "\t\tcapabilities = %lu\n",
  93                        debug->panel->link_info.capabilities);
  94        if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
  95                goto error;
  96
  97        rc = snprintf(buf + len, max_size,
  98                        "\tdp_panel_info:\n\t\tactive = %dx%d\n",
  99                        drm_mode->hdisplay,
 100                        drm_mode->vdisplay);
 101        if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 102                goto error;
 103
 104        rc = snprintf(buf + len, max_size,
 105                        "\t\tback_porch = %dx%d\n",
 106                        drm_mode->htotal - drm_mode->hsync_end,
 107                        drm_mode->vtotal - drm_mode->vsync_end);
 108        if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 109                goto error;
 110
 111        rc = snprintf(buf + len, max_size,
 112                        "\t\tfront_porch = %dx%d\n",
 113                        drm_mode->hsync_start - drm_mode->hdisplay,
 114                        drm_mode->vsync_start - drm_mode->vdisplay);
 115        if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 116                goto error;
 117
 118        rc = snprintf(buf + len, max_size,
 119                        "\t\tsync_width = %dx%d\n",
 120                        drm_mode->hsync_end - drm_mode->hsync_start,
 121                        drm_mode->vsync_end - drm_mode->vsync_start);
 122        if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 123                goto error;
 124
 125        rc = snprintf(buf + len, max_size,
 126                        "\t\tactive_low = %dx%d\n",
 127                        debug->panel->dp_mode.h_active_low,
 128                        debug->panel->dp_mode.v_active_low);
 129        if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 130                goto error;
 131
 132        rc = snprintf(buf + len, max_size,
 133                        "\t\th_skew = %d\n",
 134                        drm_mode->hskew);
 135        if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 136                goto error;
 137
 138        rc = snprintf(buf + len, max_size,
 139                        "\t\trefresh rate = %d\n",
 140                        drm_mode_vrefresh(drm_mode));
 141        if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 142                goto error;
 143
 144        rc = snprintf(buf + len, max_size,
 145                        "\t\tpixel clock khz = %d\n",
 146                        drm_mode->clock);
 147        if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 148                goto error;
 149
 150        rc = snprintf(buf + len, max_size,
 151                        "\t\tbpp = %d\n",
 152                        debug->panel->dp_mode.bpp);
 153        if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 154                goto error;
 155
 156        /* Link Information */
 157        rc = snprintf(buf + len, max_size,
 158                        "\tdp_link:\n\t\ttest_requested = %d\n",
 159                        debug->link->sink_request);
 160        if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 161                goto error;
 162
 163        rc = snprintf(buf + len, max_size,
 164                        "\t\tnum_lanes = %d\n",
 165                        debug->link->link_params.num_lanes);
 166        if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 167                goto error;
 168
 169        link_params_rate = debug->link->link_params.rate;
 170        rc = snprintf(buf + len, max_size,
 171                        "\t\tbw_code = %d\n",
 172                        drm_dp_link_rate_to_bw_code(link_params_rate));
 173        if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 174                goto error;
 175
 176        lclk = debug->link->link_params.rate * 1000;
 177        rc = snprintf(buf + len, max_size,
 178                        "\t\tlclk = %lld\n", lclk);
 179        if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 180                goto error;
 181
 182        rc = snprintf(buf + len, max_size,
 183                        "\t\tv_level = %d\n",
 184                        debug->link->phy_params.v_level);
 185        if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 186                goto error;
 187
 188        rc = snprintf(buf + len, max_size,
 189                        "\t\tp_level = %d\n",
 190                        debug->link->phy_params.p_level);
 191        if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 192                goto error;
 193
 194        if (copy_to_user(user_buff, buf, len))
 195                goto error;
 196
 197        *ppos += len;
 198
 199        kfree(buf);
 200        return len;
 201 error:
 202        kfree(buf);
 203        return -EINVAL;
 204}
 205
 206static int dp_test_data_show(struct seq_file *m, void *data)
 207{
 208        struct drm_device *dev;
 209        struct dp_debug_private *debug;
 210        struct drm_connector *connector;
 211        struct drm_connector_list_iter conn_iter;
 212        u32 bpc;
 213
 214        debug = m->private;
 215        dev = debug->drm_dev;
 216        drm_connector_list_iter_begin(dev, &conn_iter);
 217        drm_for_each_connector_iter(connector, &conn_iter) {
 218
 219                if (connector->connector_type !=
 220                        DRM_MODE_CONNECTOR_DisplayPort)
 221                        continue;
 222
 223                if (connector->status == connector_status_connected) {
 224                        bpc = debug->link->test_video.test_bit_depth;
 225                        seq_printf(m, "hdisplay: %d\n",
 226                                        debug->link->test_video.test_h_width);
 227                        seq_printf(m, "vdisplay: %d\n",
 228                                        debug->link->test_video.test_v_height);
 229                        seq_printf(m, "bpc: %u\n",
 230                                        dp_link_bit_depth_to_bpc(bpc));
 231                } else
 232                        seq_puts(m, "0");
 233        }
 234
 235        drm_connector_list_iter_end(&conn_iter);
 236
 237        return 0;
 238}
 239DEFINE_SHOW_ATTRIBUTE(dp_test_data);
 240
 241static int dp_test_type_show(struct seq_file *m, void *data)
 242{
 243        struct dp_debug_private *debug = m->private;
 244        struct drm_device *dev = debug->drm_dev;
 245        struct drm_connector *connector;
 246        struct drm_connector_list_iter conn_iter;
 247
 248        drm_connector_list_iter_begin(dev, &conn_iter);
 249        drm_for_each_connector_iter(connector, &conn_iter) {
 250
 251                if (connector->connector_type !=
 252                        DRM_MODE_CONNECTOR_DisplayPort)
 253                        continue;
 254
 255                if (connector->status == connector_status_connected)
 256                        seq_printf(m, "%02x", DP_TEST_LINK_VIDEO_PATTERN);
 257                else
 258                        seq_puts(m, "0");
 259        }
 260        drm_connector_list_iter_end(&conn_iter);
 261
 262        return 0;
 263}
 264DEFINE_SHOW_ATTRIBUTE(dp_test_type);
 265
 266static ssize_t dp_test_active_write(struct file *file,
 267                const char __user *ubuf,
 268                size_t len, loff_t *offp)
 269{
 270        char *input_buffer;
 271        int status = 0;
 272        struct dp_debug_private *debug;
 273        struct drm_device *dev;
 274        struct drm_connector *connector;
 275        struct drm_connector_list_iter conn_iter;
 276        int val = 0;
 277
 278        debug = ((struct seq_file *)file->private_data)->private;
 279        dev = debug->drm_dev;
 280
 281        if (len == 0)
 282                return 0;
 283
 284        input_buffer = memdup_user_nul(ubuf, len);
 285        if (IS_ERR(input_buffer))
 286                return PTR_ERR(input_buffer);
 287
 288        DRM_DEBUG_DRIVER("Copied %d bytes from user\n", (unsigned int)len);
 289
 290        drm_connector_list_iter_begin(dev, &conn_iter);
 291        drm_for_each_connector_iter(connector, &conn_iter) {
 292                if (connector->connector_type !=
 293                        DRM_MODE_CONNECTOR_DisplayPort)
 294                        continue;
 295
 296                if (connector->status == connector_status_connected) {
 297                        status = kstrtoint(input_buffer, 10, &val);
 298                        if (status < 0)
 299                                break;
 300                        DRM_DEBUG_DRIVER("Got %d for test active\n", val);
 301                        /* To prevent erroneous activation of the compliance
 302                         * testing code, only accept an actual value of 1 here
 303                         */
 304                        if (val == 1)
 305                                debug->panel->video_test = true;
 306                        else
 307                                debug->panel->video_test = false;
 308                }
 309        }
 310        drm_connector_list_iter_end(&conn_iter);
 311        kfree(input_buffer);
 312        if (status < 0)
 313                return status;
 314
 315        *offp += len;
 316        return len;
 317}
 318
 319static int dp_test_active_show(struct seq_file *m, void *data)
 320{
 321        struct dp_debug_private *debug = m->private;
 322        struct drm_device *dev = debug->drm_dev;
 323        struct drm_connector *connector;
 324        struct drm_connector_list_iter conn_iter;
 325
 326        drm_connector_list_iter_begin(dev, &conn_iter);
 327        drm_for_each_connector_iter(connector, &conn_iter) {
 328                if (connector->connector_type !=
 329                        DRM_MODE_CONNECTOR_DisplayPort)
 330                        continue;
 331
 332                if (connector->status == connector_status_connected) {
 333                        if (debug->panel->video_test)
 334                                seq_puts(m, "1");
 335                        else
 336                                seq_puts(m, "0");
 337                } else
 338                        seq_puts(m, "0");
 339        }
 340        drm_connector_list_iter_end(&conn_iter);
 341
 342        return 0;
 343}
 344
 345static int dp_test_active_open(struct inode *inode,
 346                struct file *file)
 347{
 348        return single_open(file, dp_test_active_show,
 349                        inode->i_private);
 350}
 351
 352static const struct file_operations dp_debug_fops = {
 353        .open = simple_open,
 354        .read = dp_debug_read_info,
 355};
 356
 357static const struct file_operations test_active_fops = {
 358        .owner = THIS_MODULE,
 359        .open = dp_test_active_open,
 360        .read = seq_read,
 361        .llseek = seq_lseek,
 362        .release = single_release,
 363        .write = dp_test_active_write
 364};
 365
 366static int dp_debug_init(struct dp_debug *dp_debug, struct drm_minor *minor)
 367{
 368        int rc = 0;
 369        struct dp_debug_private *debug = container_of(dp_debug,
 370                        struct dp_debug_private, dp_debug);
 371
 372        debugfs_create_file("dp_debug", 0444, minor->debugfs_root,
 373                        debug, &dp_debug_fops);
 374
 375        debugfs_create_file("msm_dp_test_active", 0444,
 376                        minor->debugfs_root,
 377                        debug, &test_active_fops);
 378
 379        debugfs_create_file("msm_dp_test_data", 0444,
 380                        minor->debugfs_root,
 381                        debug, &dp_test_data_fops);
 382
 383        debugfs_create_file("msm_dp_test_type", 0444,
 384                        minor->debugfs_root,
 385                        debug, &dp_test_type_fops);
 386
 387        debug->root = minor->debugfs_root;
 388
 389        return rc;
 390}
 391
 392struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel,
 393                struct dp_usbpd *usbpd, struct dp_link *link,
 394                struct drm_connector **connector, struct drm_minor *minor)
 395{
 396        int rc = 0;
 397        struct dp_debug_private *debug;
 398        struct dp_debug *dp_debug;
 399
 400        if (!dev || !panel || !usbpd || !link) {
 401                DRM_ERROR("invalid input\n");
 402                rc = -EINVAL;
 403                goto error;
 404        }
 405
 406        debug = devm_kzalloc(dev, sizeof(*debug), GFP_KERNEL);
 407        if (!debug) {
 408                rc = -ENOMEM;
 409                goto error;
 410        }
 411
 412        debug->dp_debug.debug_en = false;
 413        debug->usbpd = usbpd;
 414        debug->link = link;
 415        debug->panel = panel;
 416        debug->dev = dev;
 417        debug->drm_dev = minor->dev;
 418        debug->connector = connector;
 419
 420        dp_debug = &debug->dp_debug;
 421        dp_debug->vdisplay = 0;
 422        dp_debug->hdisplay = 0;
 423        dp_debug->vrefresh = 0;
 424
 425        rc = dp_debug_init(dp_debug, minor);
 426        if (rc) {
 427                devm_kfree(dev, debug);
 428                goto error;
 429        }
 430
 431        return dp_debug;
 432 error:
 433        return ERR_PTR(rc);
 434}
 435
 436static int dp_debug_deinit(struct dp_debug *dp_debug)
 437{
 438        struct dp_debug_private *debug;
 439
 440        if (!dp_debug)
 441                return -EINVAL;
 442
 443        debug = container_of(dp_debug, struct dp_debug_private, dp_debug);
 444
 445        debugfs_remove_recursive(debug->root);
 446
 447        return 0;
 448}
 449
 450void dp_debug_put(struct dp_debug *dp_debug)
 451{
 452        struct dp_debug_private *debug;
 453
 454        if (!dp_debug)
 455                return;
 456
 457        debug = container_of(dp_debug, struct dp_debug_private, dp_debug);
 458
 459        dp_debug_deinit(dp_debug);
 460
 461        devm_kfree(debug->dev, debug);
 462}
 463