]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
drm/hisilicon/hibmc: Add colorbar-cfg feature and its debugfs file
authorBaihan Li <libaihan@huawei.com>
Mon, 31 Mar 2025 07:42:09 +0000 (15:42 +0800)
committerDmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Fri, 11 Apr 2025 11:42:12 +0000 (14:42 +0300)
DP controller can support generating a color bar signal over the
DisplayPort interface. This can be useful to check for possible DDR
or GPU problems, as the signal generator resides completely in the DP
block. Add debugfs file that controls colorbar generator.

echo: config the color bar register to display
cat: print the color bar configuration

Signed-off-by: Baihan Li <libaihan@huawei.com>
Signed-off-by: Yongbang Shi <shiyongbang@huawei.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Link: https://lore.kernel.org/r/20250331074212.3370287-7-shiyongbang@huawei.com
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
drivers/gpu/drm/hisilicon/hibmc/Makefile
drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c
drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h
drivers/gpu/drm/hisilicon/hibmc/dp/dp_reg.h
drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_debugfs.c [new file with mode: 0644]
drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c
drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h

index 43de077d6769a52e1c1aff46a40265ca6f1651a1..1f65c683282f9a2f5e319197e4acc289f2fe3b5e 100644 (file)
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_vdac.o hibmc_drm_i2c.o \
-              dp/dp_aux.o dp/dp_link.o dp/dp_hw.o dp/dp_serdes.o hibmc_drm_dp.o
+              dp/dp_aux.o dp/dp_link.o dp/dp_hw.o dp/dp_serdes.o hibmc_drm_dp.o \
+              hibmc_drm_debugfs.o
 
 obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc-drm.o
index aa9354a996c9a9ef9501bc0dbff07dc816f88427..ce7cb07815b22b654d85d76895dbd2819636e452 100644 (file)
@@ -226,3 +226,46 @@ int hibmc_dp_mode_set(struct hibmc_dp *dp, struct drm_display_mode *mode)
 
        return 0;
 }
+
+static const struct hibmc_dp_color_raw g_rgb_raw[] = {
+       {CBAR_COLOR_BAR, 0x000, 0x000, 0x000},
+       {CBAR_WHITE,     0xfff, 0xfff, 0xfff},
+       {CBAR_RED,       0xfff, 0x000, 0x000},
+       {CBAR_ORANGE,    0xfff, 0x800, 0x000},
+       {CBAR_YELLOW,    0xfff, 0xfff, 0x000},
+       {CBAR_GREEN,     0x000, 0xfff, 0x000},
+       {CBAR_CYAN,      0x000, 0x800, 0x800},
+       {CBAR_BLUE,      0x000, 0x000, 0xfff},
+       {CBAR_PURPLE,    0x800, 0x000, 0x800},
+       {CBAR_BLACK,     0x000, 0x000, 0x000},
+};
+
+void hibmc_dp_set_cbar(struct hibmc_dp *dp, const struct hibmc_dp_cbar_cfg *cfg)
+{
+       struct hibmc_dp_dev *dp_dev = dp->dp_dev;
+       struct hibmc_dp_color_raw raw_data;
+
+       if (cfg->enable) {
+               hibmc_dp_reg_write_field(dp_dev, HIBMC_DP_COLOR_BAR_CTRL, BIT(9),
+                                        cfg->self_timing);
+               hibmc_dp_reg_write_field(dp_dev, HIBMC_DP_COLOR_BAR_CTRL, GENMASK(8, 1),
+                                        cfg->dynamic_rate);
+               if (cfg->pattern == CBAR_COLOR_BAR) {
+                       hibmc_dp_reg_write_field(dp_dev, HIBMC_DP_COLOR_BAR_CTRL, BIT(10), 0);
+               } else {
+                       raw_data = g_rgb_raw[cfg->pattern];
+                       drm_dbg_dp(dp->drm_dev, "r:%x g:%x b:%x\n", raw_data.r_value,
+                                  raw_data.g_value, raw_data.b_value);
+                       hibmc_dp_reg_write_field(dp_dev, HIBMC_DP_COLOR_BAR_CTRL, BIT(10), 1);
+                       hibmc_dp_reg_write_field(dp_dev, HIBMC_DP_COLOR_BAR_CTRL, GENMASK(23, 12),
+                                                raw_data.r_value);
+                       hibmc_dp_reg_write_field(dp_dev, HIBMC_DP_COLOR_BAR_CTRL1, GENMASK(23, 12),
+                                                raw_data.g_value);
+                       hibmc_dp_reg_write_field(dp_dev, HIBMC_DP_COLOR_BAR_CTRL1, GENMASK(11, 0),
+                                                raw_data.b_value);
+               }
+       }
+
+       hibmc_dp_reg_write_field(dp_dev, HIBMC_DP_COLOR_BAR_CTRL, BIT(0), cfg->enable);
+       writel(HIBMC_DP_SYNC_EN_MASK, dp_dev->base + HIBMC_DP_TIMING_SYNC_CTRL);
+}
index 53b6d0beecea0a054bef890d66ce16b5abb37d60..83a53dae80120976540ccf033699fdf57226c019 100644 (file)
 
 struct hibmc_dp_dev;
 
+enum hibmc_dp_cbar_pattern {
+       CBAR_COLOR_BAR,
+       CBAR_WHITE,
+       CBAR_RED,
+       CBAR_ORANGE,
+       CBAR_YELLOW,
+       CBAR_GREEN,
+       CBAR_CYAN,
+       CBAR_BLUE,
+       CBAR_PURPLE,
+       CBAR_BLACK,
+};
+
+struct hibmc_dp_color_raw {
+       enum hibmc_dp_cbar_pattern pattern;
+       u32 r_value;
+       u32 g_value;
+       u32 b_value;
+};
+
+struct hibmc_dp_cbar_cfg {
+       u8 enable;
+       u8 self_timing;
+       u8 dynamic_rate; /* 0:static, 1-255(frame):dynamic */
+       enum hibmc_dp_cbar_pattern pattern;
+};
+
 struct hibmc_dp {
        struct hibmc_dp_dev *dp_dev;
        struct drm_device *drm_dev;
@@ -21,10 +48,12 @@ struct hibmc_dp {
        struct drm_connector connector;
        void __iomem *mmio;
        struct drm_dp_aux aux;
+       struct hibmc_dp_cbar_cfg cfg;
 };
 
 int hibmc_dp_hw_init(struct hibmc_dp *dp);
 int hibmc_dp_mode_set(struct hibmc_dp *dp, struct drm_display_mode *mode);
 void hibmc_dp_display_en(struct hibmc_dp *dp, bool enable);
+void hibmc_dp_set_cbar(struct hibmc_dp *dp, const struct hibmc_dp_cbar_cfg *cfg);
 
 #endif
index 6eb76decc636e3d0d53d0ffc5dafd9538ae569a9..5614b727a710ecda02b02c1b86722c9e028cb61f 100644 (file)
@@ -67,6 +67,9 @@
 #define HIBMC_DP_CFG_STREAM_HTOTAL_SIZE                GENMASK(31, 16)
 #define HIBMC_DP_CFG_STREAM_HBLANK_SIZE                GENMASK(15, 0)
 
+#define HIBMC_DP_COLOR_BAR_CTRL                        0x260
+#define HIBMC_DP_COLOR_BAR_CTRL1               0x264
+
 #define HIBMC_DP_TIMING_GEN_CONFIG0            0x26c
 #define HIBMC_DP_CFG_TIMING_GEN0_HACTIVE       GENMASK(31, 16)
 #define HIBMC_DP_CFG_TIMING_GEN0_HBLANK                GENMASK(15, 0)
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_debugfs.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_debugfs.c
new file mode 100644 (file)
index 0000000..f585387
--- /dev/null
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// Copyright (c) 2024 Hisilicon Limited.
+
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/seq_file.h>
+#include <linux/pci.h>
+
+#include <drm/drm_drv.h>
+#include <drm/drm_file.h>
+#include <drm/drm_debugfs.h>
+#include <drm/drm_edid.h>
+
+#include "hibmc_drm_drv.h"
+
+#define MAX_BUF_SIZE 12
+
+static ssize_t hibmc_control_write(struct file *file, const char __user *user_buf,
+                                  size_t count, loff_t *ppos)
+{
+       struct hibmc_drm_private *priv = file_inode(file)->i_private;
+       struct hibmc_dp_cbar_cfg *cfg = &priv->dp.cfg;
+       int ret, idx;
+       u8 buf[MAX_BUF_SIZE];
+
+       if (count >= MAX_BUF_SIZE)
+               return -EINVAL;
+
+       if (copy_from_user(buf, user_buf, count))
+               return -EFAULT;
+
+       buf[count] = '\0';
+
+       /* Only 4 parameters is allowed, the ranger are as follow:
+        * [0] enable/disable colorbar feature
+              0: enable colorbar, 1: disable colorbar
+        * [1] the timing source of colorbar displaying
+              0: timing follows XDP, 1: internal self timing
+        * [2] the movment of colorbar displaying
+              0: static colorbar image,
+        *     1~255: right shifting a type of color per (1~255)frames
+        * [3] the color type of colorbar displaying
+              0~9: color bar, white, red, orange,
+        *          yellow, green, cyan, bule, pupper, black
+        */
+       if (sscanf(buf, "%hhu %hhu %hhu %u", &cfg->enable, &cfg->self_timing,
+                  &cfg->dynamic_rate, &cfg->pattern) != 4) {
+               return -EINVAL;
+       }
+
+       if (cfg->pattern > 9 || cfg->enable > 1 || cfg->self_timing > 1)
+               return -EINVAL;
+
+       ret = drm_dev_enter(&priv->dev, &idx);
+       if (!ret)
+               return -ENODEV;
+
+       hibmc_dp_set_cbar(&priv->dp, cfg);
+
+       drm_dev_exit(idx);
+
+       return count;
+}
+
+static int hibmc_dp_dbgfs_show(struct seq_file *m, void *arg)
+{
+       struct hibmc_drm_private *priv = m->private;
+       struct hibmc_dp_cbar_cfg *cfg = &priv->dp.cfg;
+       int idx;
+
+       if (!drm_dev_enter(&priv->dev, &idx))
+               return -ENODEV;
+
+       seq_printf(m, "hibmc dp colorbar cfg: %u %u %u %u\n", cfg->enable, cfg->self_timing,
+                  cfg->dynamic_rate, cfg->pattern);
+
+       drm_dev_exit(idx);
+
+       return 0;
+}
+
+static int hibmc_open(struct inode *inode, struct file *filp)
+{
+       return single_open(filp, hibmc_dp_dbgfs_show, inode->i_private);
+}
+
+static const struct file_operations hibmc_dbg_fops = {
+       .owner   = THIS_MODULE,
+       .write   = hibmc_control_write,
+       .read    = seq_read,
+       .open    = hibmc_open,
+       .llseek  = seq_lseek,
+       .release = single_release,
+};
+
+void hibmc_debugfs_init(struct drm_connector *connector, struct dentry *root)
+{
+       struct drm_device *dev = connector->dev;
+       struct hibmc_drm_private *priv = to_hibmc_drm_private(dev);
+
+       /* create the file in drm directory, so we don't need to remove manually */
+       debugfs_create_file("colorbar-cfg", 0200,
+                           root, priv, &hibmc_dbg_fops);
+}
index 8e5ee816dfbd918aeba30cd302d83739c4368409..a86ecce4b3c14dc4563a932c00458631b91ccaef 100644 (file)
@@ -55,6 +55,7 @@ static const struct drm_connector_funcs hibmc_dp_conn_funcs = {
        .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
        .late_register = hibmc_dp_late_register,
        .early_unregister = hibmc_dp_early_unregister,
+       .debugfs_init = hibmc_debugfs_init,
 };
 
 static inline int hibmc_dp_prepare(struct hibmc_dp *dp, struct drm_display_mode *mode)
index 3ddd71aada66a9b0053ab0be8c0fe4defc72fe4f..bc89e4b9f4e3ca45d1e3eb30a95555af1d5196b8 100644 (file)
@@ -69,4 +69,6 @@ int hibmc_ddc_create(struct drm_device *drm_dev, struct hibmc_vdac *connector);
 
 int hibmc_dp_init(struct hibmc_drm_private *priv);
 
+void hibmc_debugfs_init(struct drm_connector *connector, struct dentry *root);
+
 #endif