Those patches introduce debugfs for connector, encoder, crtc and planes. It adds the following entries: - planes: gdpx / gdpx_node hqvdp cursor vid fps_get / fps_show
- crtc: mixer_aux / mixer_main
- encoder: tvout
- connectors: hda hdmi dvo
Vincent Abriou (10): drm/sti: add debugfs entries for HDMI connector drm/sti: add debugfs entries for DVO connector drm/sti: add debugfs entries for HDA connector drm/sti: add debugfs entries for CURSOR plane drm/sti: add debugfs entries for GDP planes drm/sti: add debugfs entries for HQVDP plane drm/sti: add debugfs entries for VID plane drm/sti: add debugfs entries for MIXER crtc drm/sti: add debugfs entries for TVOUT encoders drm/sti: add debugfs fps_show/fps_get mechanism for planes
drivers/gpu/drm/sti/sti_compositor.c | 4 +- drivers/gpu/drm/sti/sti_cursor.c | 81 +++++++++++ drivers/gpu/drm/sti/sti_drv.c | 128 ++++++++++++++++++ drivers/gpu/drm/sti/sti_dvo.c | 70 ++++++++++ drivers/gpu/drm/sti/sti_gdp.c | 238 ++++++++++++++++++++++++++++++++ drivers/gpu/drm/sti/sti_hda.c | 105 ++++++++++++++- drivers/gpu/drm/sti/sti_hdmi.c | 175 +++++++++++++++++++++++- drivers/gpu/drm/sti/sti_hdmi.h | 4 +- drivers/gpu/drm/sti/sti_hqvdp.c | 254 ++++++++++++++++++++++++++++++++++- drivers/gpu/drm/sti/sti_mixer.c | 146 +++++++++++++++++++- drivers/gpu/drm/sti/sti_mixer.h | 4 +- drivers/gpu/drm/sti/sti_plane.c | 63 +++++++++ drivers/gpu/drm/sti/sti_plane.h | 17 +++ drivers/gpu/drm/sti/sti_tvout.c | 157 ++++++++++++++++++++++ drivers/gpu/drm/sti/sti_vid.c | 94 ++++++++++++- drivers/gpu/drm/sti/sti_vid.h | 4 +- 16 files changed, 1524 insertions(+), 20 deletions(-)
Signed-off-by: Vincent Abriou vincent.abriou@st.com --- drivers/gpu/drm/sti/sti_hdmi.c | 175 ++++++++++++++++++++++++++++++++++++++++- drivers/gpu/drm/sti/sti_hdmi.h | 4 +- 2 files changed, 175 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c index 69a2286..6ef0715 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.c +++ b/drivers/gpu/drm/sti/sti_hdmi.c @@ -6,6 +6,7 @@
#include <linux/clk.h> #include <linux/component.h> +#include <linux/debugfs.h> #include <linux/hdmi.h> #include <linux/module.h> #include <linux/of_gpio.h> @@ -550,6 +551,172 @@ static void hdmi_swreset(struct sti_hdmi *hdmi) clk_disable_unprepare(hdmi->clk_audio); }
+#define DBGFS_PRINT_STR(str1, str2) seq_printf(s, "%-24s %s\n", str1, str2) +#define DBGFS_PRINT_INT(str1, int2) seq_printf(s, "%-24s %d\n", str1, int2) +#define DBGFS_DUMP(str, reg) seq_printf(s, "%s %-25s 0x%08X", str, #reg, \ + hdmi_read(hdmi, reg)) +#define DBGFS_DUMP_DI(reg, slot) DBGFS_DUMP("\n", reg(slot)) + +static void hdmi_dbg_cfg(struct seq_file *s, int val) +{ + int tmp; + + seq_puts(s, "\t"); + tmp = val & HDMI_CFG_HDMI_NOT_DVI; + DBGFS_PRINT_STR("mode:", tmp ? "HDMI" : "DVI"); + seq_puts(s, "\t\t\t\t\t"); + tmp = val & HDMI_CFG_HDCP_EN; + DBGFS_PRINT_STR("HDCP:", tmp ? "enable" : "disable"); + seq_puts(s, "\t\t\t\t\t"); + tmp = val & HDMI_CFG_ESS_NOT_OESS; + DBGFS_PRINT_STR("HDCP mode:", tmp ? "ESS enable" : "OESS enable"); + seq_puts(s, "\t\t\t\t\t"); + tmp = val & HDMI_CFG_SINK_TERM_DET_EN; + DBGFS_PRINT_STR("Sink term detection:", tmp ? "enable" : "disable"); + seq_puts(s, "\t\t\t\t\t"); + tmp = val & HDMI_CFG_H_SYNC_POL_NEG; + DBGFS_PRINT_STR("Hsync polarity:", tmp ? "inverted" : "normal"); + seq_puts(s, "\t\t\t\t\t"); + tmp = val & HDMI_CFG_V_SYNC_POL_NEG; + DBGFS_PRINT_STR("Vsync polarity:", tmp ? "inverted" : "normal"); + seq_puts(s, "\t\t\t\t\t"); + tmp = val & HDMI_CFG_422_EN; + DBGFS_PRINT_STR("YUV422 format:", tmp ? "enable" : "disable"); +} + +static void hdmi_dbg_sta(struct seq_file *s, int val) +{ + int tmp; + + seq_puts(s, "\t"); + tmp = (val & HDMI_STA_DLL_LCK); + DBGFS_PRINT_STR("pll:", tmp ? "locked" : "not locked"); + seq_puts(s, "\t\t\t\t\t"); + tmp = (val & HDMI_STA_HOT_PLUG); + DBGFS_PRINT_STR("hdmi cable:", tmp ? "connected" : "not connected"); +} + +static void hdmi_dbg_sw_di_cfg(struct seq_file *s, int val) +{ + int tmp; + char *const en_di[] = {"no transmission", + "single transmission", + "once every field", + "once every frame"}; + + seq_puts(s, "\t"); + tmp = (val & HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, 1)); + DBGFS_PRINT_STR("Data island 1:", en_di[tmp]); + seq_puts(s, "\t\t\t\t\t"); + tmp = (val & HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, 2)) >> 4; + DBGFS_PRINT_STR("Data island 2:", en_di[tmp]); + seq_puts(s, "\t\t\t\t\t"); + tmp = (val & HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, 3)) >> 8; + DBGFS_PRINT_STR("Data island 3:", en_di[tmp]); + seq_puts(s, "\t\t\t\t\t"); + tmp = (val & HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, 4)) >> 12; + DBGFS_PRINT_STR("Data island 4:", en_di[tmp]); + seq_puts(s, "\t\t\t\t\t"); + tmp = (val & HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, 5)) >> 16; + DBGFS_PRINT_STR("Data island 5:", en_di[tmp]); + seq_puts(s, "\t\t\t\t\t"); + tmp = (val & HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, 6)) >> 20; + DBGFS_PRINT_STR("Data island 6:", en_di[tmp]); +} + +static int hdmi_dbg_show(struct seq_file *s, void *data) +{ + struct drm_info_node *node = s->private; + struct sti_hdmi *hdmi = (struct sti_hdmi *)node->info_ent->data; + struct drm_device *dev = node->minor->dev; + int ret; + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; + + seq_printf(s, "HDMI: (vaddr = 0x%p)", hdmi->regs); + DBGFS_DUMP("\n", HDMI_CFG); + hdmi_dbg_cfg(s, hdmi_read(hdmi, HDMI_CFG)); + DBGFS_DUMP("", HDMI_INT_EN); + DBGFS_DUMP("\n", HDMI_STA); + hdmi_dbg_sta(s, hdmi_read(hdmi, HDMI_STA)); + DBGFS_DUMP("", HDMI_ACTIVE_VID_XMIN); + seq_puts(s, "\t"); + DBGFS_PRINT_INT("Xmin:", hdmi_read(hdmi, HDMI_ACTIVE_VID_XMIN)); + DBGFS_DUMP("", HDMI_ACTIVE_VID_XMAX); + seq_puts(s, "\t"); + DBGFS_PRINT_INT("Xmax:", hdmi_read(hdmi, HDMI_ACTIVE_VID_XMAX)); + DBGFS_DUMP("", HDMI_ACTIVE_VID_YMIN); + seq_puts(s, "\t"); + DBGFS_PRINT_INT("Ymin:", hdmi_read(hdmi, HDMI_ACTIVE_VID_YMIN)); + DBGFS_DUMP("", HDMI_ACTIVE_VID_YMAX); + seq_puts(s, "\t"); + DBGFS_PRINT_INT("Ymax:", hdmi_read(hdmi, HDMI_ACTIVE_VID_YMAX)); + DBGFS_DUMP("", HDMI_SW_DI_CFG); + hdmi_dbg_sw_di_cfg(s, hdmi_read(hdmi, HDMI_SW_DI_CFG)); + + seq_printf(s, "\n AVI Infoframe (Data Island slot N=%d):", + HDMI_IFRAME_SLOT_AVI); + DBGFS_DUMP_DI(HDMI_SW_DI_N_HEAD_WORD, HDMI_IFRAME_SLOT_AVI); + DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD0, HDMI_IFRAME_SLOT_AVI); + DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD1, HDMI_IFRAME_SLOT_AVI); + DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD2, HDMI_IFRAME_SLOT_AVI); + DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD3, HDMI_IFRAME_SLOT_AVI); + DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD4, HDMI_IFRAME_SLOT_AVI); + DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD5, HDMI_IFRAME_SLOT_AVI); + DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD6, HDMI_IFRAME_SLOT_AVI); + seq_puts(s, "\n"); + seq_printf(s, "\n AUDIO Infoframe (Data Island slot N=%d):", + HDMI_IFRAME_SLOT_AUDIO); + DBGFS_DUMP_DI(HDMI_SW_DI_N_HEAD_WORD, HDMI_IFRAME_SLOT_AUDIO); + DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD0, HDMI_IFRAME_SLOT_AUDIO); + DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD1, HDMI_IFRAME_SLOT_AUDIO); + DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD2, HDMI_IFRAME_SLOT_AUDIO); + DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD3, HDMI_IFRAME_SLOT_AUDIO); + DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD4, HDMI_IFRAME_SLOT_AUDIO); + DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD5, HDMI_IFRAME_SLOT_AUDIO); + DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD6, HDMI_IFRAME_SLOT_AUDIO); + seq_puts(s, "\n"); + seq_printf(s, "\n VENDOR SPECIFIC Infoframe (Data Island slot N=%d):", + HDMI_IFRAME_SLOT_VENDOR); + DBGFS_DUMP_DI(HDMI_SW_DI_N_HEAD_WORD, HDMI_IFRAME_SLOT_VENDOR); + DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD0, HDMI_IFRAME_SLOT_VENDOR); + DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD1, HDMI_IFRAME_SLOT_VENDOR); + DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD2, HDMI_IFRAME_SLOT_VENDOR); + DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD3, HDMI_IFRAME_SLOT_VENDOR); + DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD4, HDMI_IFRAME_SLOT_VENDOR); + DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD5, HDMI_IFRAME_SLOT_VENDOR); + DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD6, HDMI_IFRAME_SLOT_VENDOR); + seq_puts(s, "\n"); + + mutex_unlock(&dev->struct_mutex); + return 0; +} + +static struct drm_info_list hdmi_debugfs_files[] = { + { "hdmi", hdmi_dbg_show, 0, NULL }, +}; + +static void hdmi_debugfs_exit(struct sti_hdmi *hdmi, struct drm_minor *minor) +{ + drm_debugfs_remove_files(hdmi_debugfs_files, + ARRAY_SIZE(hdmi_debugfs_files), + minor); +} + +static int hdmi_debugfs_init(struct sti_hdmi *hdmi, struct drm_minor *minor) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(hdmi_debugfs_files); i++) + hdmi_debugfs_files[i].data = hdmi; + + return drm_debugfs_create_files(hdmi_debugfs_files, + ARRAY_SIZE(hdmi_debugfs_files), + minor->debugfs_root, minor); +} + static void sti_hdmi_disable(struct drm_bridge *bridge) { struct sti_hdmi *hdmi = bridge->driver_private; @@ -941,6 +1108,9 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data) /* Enable default interrupts */ hdmi_write(hdmi, HDMI_DEFAULT_INT, HDMI_INT_EN);
+ if (hdmi_debugfs_init(hdmi, drm_dev->primary)) + DRM_ERROR("HDMI debugfs setup failed\n"); + return 0;
err_sysfs: @@ -954,7 +1124,10 @@ err_connector: static void sti_hdmi_unbind(struct device *dev, struct device *master, void *data) { - /* do nothing */ + struct sti_hdmi *hdmi = dev_get_drvdata(dev); + struct drm_device *drm_dev = data; + + hdmi_debugfs_exit(hdmi, drm_dev->primary); }
static const struct component_ops sti_hdmi_ops = { diff --git a/drivers/gpu/drm/sti/sti_hdmi.h b/drivers/gpu/drm/sti/sti_hdmi.h index 77edb73..ef3a945 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.h +++ b/drivers/gpu/drm/sti/sti_hdmi.h @@ -14,9 +14,7 @@
#define HDMI_STA 0x0010 #define HDMI_STA_DLL_LCK BIT(5) - -#define HDMI_STA_HOT_PLUG_SHIFT 4 -#define HDMI_STA_HOT_PLUG (1 << HDMI_STA_HOT_PLUG_SHIFT) +#define HDMI_STA_HOT_PLUG BIT(4)
struct sti_hdmi;
Signed-off-by: Vincent Abriou vincent.abriou@st.com --- drivers/gpu/drm/sti/sti_dvo.c | 70 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+)
diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c index 9e90b74..25f7663 100644 --- a/drivers/gpu/drm/sti/sti_dvo.c +++ b/drivers/gpu/drm/sti/sti_dvo.c @@ -6,6 +6,7 @@
#include <linux/clk.h> #include <linux/component.h> +#include <linux/debugfs.h> #include <linux/module.h> #include <linux/of_gpio.h> #include <linux/platform_device.h> @@ -156,6 +157,69 @@ static void dvo_awg_configure(struct sti_dvo *dvo, u32 *awg_ram_code, int nb) writel(DVO_AWG_CTRL_EN, dvo->regs + DVO_AWG_DIGSYNC_CTRL); }
+#define DBGFS_DUMP(reg) seq_printf(s, "\n %-25s 0x%08X", #reg, \ + readl(dvo->regs + reg)) + +static void dvo_dbg_awg_microcode(struct seq_file *s, void __iomem *reg) +{ + unsigned int i; + + seq_puts(s, "\n\n"); + seq_puts(s, " DVO AWG microcode:"); + for (i = 0; i < AWG_MAX_INST; i++) { + if (i % 8 == 0) + seq_printf(s, "\n %04X:", i); + seq_printf(s, " %04X", readl(reg + i * 4)); + } +} + +static int dvo_dbg_show(struct seq_file *s, void *data) +{ + struct drm_info_node *node = s->private; + struct sti_dvo *dvo = (struct sti_dvo *)node->info_ent->data; + struct drm_device *dev = node->minor->dev; + int ret; + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; + + seq_printf(s, "DVO: (vaddr = 0x%p)", dvo->regs); + DBGFS_DUMP(DVO_AWG_DIGSYNC_CTRL); + DBGFS_DUMP(DVO_DOF_CFG); + DBGFS_DUMP(DVO_LUT_PROG_LOW); + DBGFS_DUMP(DVO_LUT_PROG_MID); + DBGFS_DUMP(DVO_LUT_PROG_HIGH); + dvo_dbg_awg_microcode(s, dvo->regs + DVO_DIGSYNC_INSTR_I); + seq_puts(s, "\n"); + + mutex_unlock(&dev->struct_mutex); + return 0; +} + +static struct drm_info_list dvo_debugfs_files[] = { + { "dvo", dvo_dbg_show, 0, NULL }, +}; + +static void dvo_debugfs_exit(struct sti_dvo *dvo, struct drm_minor *minor) +{ + drm_debugfs_remove_files(dvo_debugfs_files, + ARRAY_SIZE(dvo_debugfs_files), + minor); +} + +static int dvo_debugfs_init(struct sti_dvo *dvo, struct drm_minor *minor) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(dvo_debugfs_files); i++) + dvo_debugfs_files[i].data = dvo; + + return drm_debugfs_create_files(dvo_debugfs_files, + ARRAY_SIZE(dvo_debugfs_files), + minor->debugfs_root, minor); +} + static void sti_dvo_disable(struct drm_bridge *bridge) { struct sti_dvo *dvo = bridge->driver_private; @@ -455,6 +519,9 @@ static int sti_dvo_bind(struct device *dev, struct device *master, void *data) goto err_sysfs; }
+ if (dvo_debugfs_init(dvo, drm_dev->primary)) + DRM_ERROR("DVO debugfs setup failed\n"); + return 0;
err_sysfs: @@ -469,6 +536,9 @@ static void sti_dvo_unbind(struct device *dev, struct device *master, void *data) { struct sti_dvo *dvo = dev_get_drvdata(dev); + struct drm_device *drm_dev = data; + + dvo_debugfs_exit(dvo, drm_dev->primary);
drm_bridge_remove(dvo->bridge); }
Signed-off-by: Vincent Abriou vincent.abriou@st.com --- drivers/gpu/drm/sti/sti_hda.c | 105 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 104 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c index 293a133..ec0d017 100644 --- a/drivers/gpu/drm/sti/sti_hda.c +++ b/drivers/gpu/drm/sti/sti_hda.c @@ -326,6 +326,103 @@ static void hda_enable_hd_dacs(struct sti_hda *hda, bool enable) } }
+#define DBGFS_DUMP(reg) seq_printf(s, "\n %-25s 0x%08X", #reg, \ + readl(hda->regs + reg)) + +static void hda_dbg_cfg(struct seq_file *s, int val) +{ + seq_puts(s, "\tAWG "); + seq_puts(s, val & CFG_AWG_ASYNC_EN ? "enabled" : "disabled"); +} + +static void hda_dbg_awg_microcode(struct seq_file *s, void __iomem *reg) +{ + unsigned int i; + + seq_puts(s, "\n\n"); + seq_puts(s, " HDA AWG microcode:"); + for (i = 0; i < AWG_MAX_INST; i++) { + if (i % 8 == 0) + seq_printf(s, "\n %04X:", i); + seq_printf(s, " %04X", readl(reg + i * 4)); + } +} + +static void hda_dbg_video_dacs_ctrl(struct seq_file *s, void __iomem *reg) +{ + u32 val = readl(reg); + u32 mask; + + switch ((u32)reg & VIDEO_DACS_CONTROL_MASK) { + case VIDEO_DACS_CONTROL_SYSCFG2535: + mask = DAC_CFG_HD_OFF_MASK; + break; + case VIDEO_DACS_CONTROL_SYSCFG5072: + mask = DAC_CFG_HD_HZUVW_OFF_MASK; + break; + default: + DRM_DEBUG_DRIVER("Warning: DACS ctrl register not supported!"); + return; + } + + seq_puts(s, "\n"); + seq_printf(s, "\n %-25s 0x%08X", "VIDEO_DACS_CONTROL", val); + seq_puts(s, "\tHD DACs "); + seq_puts(s, val & mask ? "disabled" : "enabled"); +} + +static int hda_dbg_show(struct seq_file *s, void *data) +{ + struct drm_info_node *node = s->private; + struct sti_hda *hda = (struct sti_hda *)node->info_ent->data; + struct drm_device *dev = node->minor->dev; + int ret; + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; + + seq_printf(s, "HD Analog: (vaddr = 0x%p)", hda->regs); + DBGFS_DUMP(HDA_ANA_CFG); + hda_dbg_cfg(s, readl(hda->regs + HDA_ANA_CFG)); + DBGFS_DUMP(HDA_ANA_SCALE_CTRL_Y); + DBGFS_DUMP(HDA_ANA_SCALE_CTRL_CB); + DBGFS_DUMP(HDA_ANA_SCALE_CTRL_CR); + DBGFS_DUMP(HDA_ANA_ANC_CTRL); + DBGFS_DUMP(HDA_ANA_SRC_Y_CFG); + DBGFS_DUMP(HDA_ANA_SRC_C_CFG); + hda_dbg_awg_microcode(s, hda->regs + HDA_SYNC_AWGI); + if (hda->video_dacs_ctrl) + hda_dbg_video_dacs_ctrl(s, hda->video_dacs_ctrl); + seq_puts(s, "\n"); + + mutex_unlock(&dev->struct_mutex); + return 0; +} + +static struct drm_info_list hda_debugfs_files[] = { + { "hda", hda_dbg_show, 0, NULL }, +}; + +static void hda_debugfs_exit(struct sti_hda *hda, struct drm_minor *minor) +{ + drm_debugfs_remove_files(hda_debugfs_files, + ARRAY_SIZE(hda_debugfs_files), + minor); +} + +static int hda_debugfs_init(struct sti_hda *hda, struct drm_minor *minor) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(hda_debugfs_files); i++) + hda_debugfs_files[i].data = hda; + + return drm_debugfs_create_files(hda_debugfs_files, + ARRAY_SIZE(hda_debugfs_files), + minor->debugfs_root, minor); +} + /** * Configure AWG, writing instructions * @@ -688,6 +785,9 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data) /* force to disable hd dacs at startup */ hda_enable_hd_dacs(hda, false);
+ if (hda_debugfs_init(hda, drm_dev->primary)) + DRM_ERROR("HDA debugfs setup failed\n"); + return 0;
err_sysfs: @@ -700,7 +800,10 @@ err_connector: static void sti_hda_unbind(struct device *dev, struct device *master, void *data) { - /* do nothing */ + struct sti_hda *hda = dev_get_drvdata(dev); + struct drm_device *drm_dev = data; + + hda_debugfs_exit(hda, drm_dev->primary); }
static const struct component_ops sti_hda_ops = {
Signed-off-by: Vincent Abriou vincent.abriou@st.com --- drivers/gpu/drm/sti/sti_cursor.c | 79 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+)
diff --git a/drivers/gpu/drm/sti/sti_cursor.c b/drivers/gpu/drm/sti/sti_cursor.c index a4c67ab..9eac1b9 100644 --- a/drivers/gpu/drm/sti/sti_cursor.c +++ b/drivers/gpu/drm/sti/sti_cursor.c @@ -72,6 +72,82 @@ static const uint32_t cursor_supported_formats[] = {
#define to_sti_cursor(x) container_of(x, struct sti_cursor, plane)
+#define DBGFS_DUMP(reg) seq_printf(s, "\n %-25s 0x%08X", #reg, \ + readl(cursor->regs + reg)) + +static void cursor_dbg_vpo(struct seq_file *s, u32 val) +{ + seq_printf(s, "\txdo:%4d\tydo:%4d", val & 0x0FFF, (val >> 16) & 0x0FFF); +} + +static void cursor_dbg_size(struct seq_file *s, u32 val) +{ + seq_printf(s, "\t%d x %d", val & 0x07FF, (val >> 16) & 0x07FF); +} + +static void cursor_dbg_pml(struct seq_file *s, + struct sti_cursor *cursor, u32 val) +{ + if (cursor->pixmap.paddr == val) + seq_printf(s, "\tVirt @: %p", cursor->pixmap.base); +} + +static void cursor_dbg_cml(struct seq_file *s, + struct sti_cursor *cursor, u32 val) +{ + if (cursor->clut_paddr == val) + seq_printf(s, "\tVirt @: %p", cursor->clut); +} + +static int cursor_dbg_show(struct seq_file *s, void *data) +{ + struct drm_info_node *node = s->private; + struct sti_cursor *cursor = (struct sti_cursor *)node->info_ent->data; + struct drm_device *dev = node->minor->dev; + int ret; + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; + + seq_printf(s, "%s: (vaddr = 0x%p)", + sti_plane_to_str(&cursor->plane), cursor->regs); + + DBGFS_DUMP(CUR_CTL); + DBGFS_DUMP(CUR_VPO); + cursor_dbg_vpo(s, readl(cursor->regs + CUR_VPO)); + DBGFS_DUMP(CUR_PML); + cursor_dbg_pml(s, cursor, readl(cursor->regs + CUR_PML)); + DBGFS_DUMP(CUR_PMP); + DBGFS_DUMP(CUR_SIZE); + cursor_dbg_size(s, readl(cursor->regs + CUR_SIZE)); + DBGFS_DUMP(CUR_CML); + cursor_dbg_cml(s, cursor, readl(cursor->regs + CUR_CML)); + DBGFS_DUMP(CUR_AWS); + DBGFS_DUMP(CUR_AWE); + seq_puts(s, "\n"); + + mutex_unlock(&dev->struct_mutex); + return 0; +} + +static struct drm_info_list cursor_debugfs_files[] = { + { "cursor", cursor_dbg_show, 0, NULL }, +}; + +static int cursor_debugfs_init(struct sti_cursor *cursor, + struct drm_minor *minor) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(cursor_debugfs_files); i++) + cursor_debugfs_files[i].data = cursor; + + return drm_debugfs_create_files(cursor_debugfs_files, + ARRAY_SIZE(cursor_debugfs_files), + minor->debugfs_root, minor); +} + static void sti_cursor_argb8888_to_clut8(struct sti_cursor *cursor, u32 *src) { u8 *dst = cursor->pixmap.base; @@ -306,6 +382,9 @@ struct drm_plane *sti_cursor_create(struct drm_device *drm_dev,
sti_plane_init_property(&cursor->plane, DRM_PLANE_TYPE_CURSOR);
+ if (cursor_debugfs_init(cursor, drm_dev->primary)) + DRM_ERROR("CURSOR debugfs setup failed\n"); + return &cursor->plane.drm_plane;
err_plane:
Signed-off-by: Vincent Abriou vincent.abriou@st.com --- drivers/gpu/drm/sti/sti_gdp.c | 236 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 236 insertions(+)
diff --git a/drivers/gpu/drm/sti/sti_gdp.c b/drivers/gpu/drm/sti/sti_gdp.c index a6fba9c..8f0e89f 100644 --- a/drivers/gpu/drm/sti/sti_gdp.c +++ b/drivers/gpu/drm/sti/sti_gdp.c @@ -31,6 +31,23 @@ #define GDP_ARGB1555 0x06 #define GDP_ARGB4444 0x07
+#define GDP2STR(fmt) { GDP_ ## fmt, #fmt } + +static struct gdp_format_to_str { + int format; + char name[20]; +} gdp_format_to_str[] = { + GDP2STR(RGB565), + GDP2STR(RGB888), + GDP2STR(RGB888_32), + GDP2STR(XBGR8888), + GDP2STR(ARGB8565), + GDP2STR(ARGB8888), + GDP2STR(ABGR8888), + GDP2STR(ARGB1555), + GDP2STR(ARGB4444) + }; + #define GAM_GDP_CTL_OFFSET 0x00 #define GAM_GDP_AGC_OFFSET 0x04 #define GAM_GDP_VPO_OFFSET 0x0C @@ -119,6 +136,222 @@ static const uint32_t gdp_supported_formats[] = { DRM_FORMAT_RGB888, };
+#define DBGFS_DUMP(reg) seq_printf(s, "\n %-25s 0x%08X", #reg, \ + readl(gdp->regs + reg ## _OFFSET)) + +static void gdp_dbg_ctl(struct seq_file *s, int val) +{ + int i; + + seq_puts(s, "\tColor:"); + for (i = 0; i < ARRAY_SIZE(gdp_format_to_str); i++) { + if (gdp_format_to_str[i].format == (val & 0x1F)) { + seq_printf(s, gdp_format_to_str[i].name); + break; + } + } + if (i == ARRAY_SIZE(gdp_format_to_str)) + seq_puts(s, "<UNKNOWN>"); + + seq_printf(s, "\tWaitNextVsync:%d", val & WAIT_NEXT_VSYNC ? 1 : 0); +} + +static void gdp_dbg_vpo(struct seq_file *s, int val) +{ + seq_printf(s, "\txdo:%4d\tydo:%4d", val & 0xFFFF, (val >> 16) & 0xFFFF); +} + +static void gdp_dbg_vps(struct seq_file *s, int val) +{ + seq_printf(s, "\txds:%4d\tyds:%4d", val & 0xFFFF, (val >> 16) & 0xFFFF); +} + +static void gdp_dbg_size(struct seq_file *s, int val) +{ + seq_printf(s, "\t%d x %d", val & 0xFFFF, (val >> 16) & 0xFFFF); +} + +static void gdp_dbg_nvn(struct seq_file *s, struct sti_gdp *gdp, int val) +{ + void *base = NULL; + unsigned int i; + + for (i = 0; i < GDP_NODE_NB_BANK; i++) { + if (gdp->node_list[i].top_field_paddr == val) { + base = gdp->node_list[i].top_field; + break; + } + if (gdp->node_list[i].btm_field_paddr == val) { + base = gdp->node_list[i].btm_field; + break; + } + } + + if (base) + seq_printf(s, "\tVirt @: %p", base); +} + +static void gdp_dbg_ppt(struct seq_file *s, int val) +{ + if (val & GAM_GDP_PPT_IGNORE) + seq_puts(s, "\tNot displayed on mixer!"); +} + +static void gdp_dbg_mst(struct seq_file *s, int val) +{ + if (val & 1) + seq_puts(s, "\tBUFFER UNDERFLOW!"); +} + +static int gdp_dbg_show(struct seq_file *s, void *data) +{ + struct drm_info_node *node = s->private; + struct sti_gdp *gdp = (struct sti_gdp *)node->info_ent->data; + struct drm_device *dev = node->minor->dev; + struct drm_plane *drm_plane = &gdp->plane.drm_plane; + struct drm_crtc *crtc = drm_plane->crtc; + int ret; + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; + + seq_printf(s, "%s: (vaddr = 0x%p)", + sti_plane_to_str(&gdp->plane), gdp->regs); + + DBGFS_DUMP(GAM_GDP_CTL); + gdp_dbg_ctl(s, readl(gdp->regs + GAM_GDP_CTL_OFFSET)); + DBGFS_DUMP(GAM_GDP_AGC); + DBGFS_DUMP(GAM_GDP_VPO); + gdp_dbg_vpo(s, readl(gdp->regs + GAM_GDP_VPO_OFFSET)); + DBGFS_DUMP(GAM_GDP_VPS); + gdp_dbg_vps(s, readl(gdp->regs + GAM_GDP_VPS_OFFSET)); + DBGFS_DUMP(GAM_GDP_PML); + DBGFS_DUMP(GAM_GDP_PMP); + DBGFS_DUMP(GAM_GDP_SIZE); + gdp_dbg_size(s, readl(gdp->regs + GAM_GDP_SIZE_OFFSET)); + DBGFS_DUMP(GAM_GDP_NVN); + gdp_dbg_nvn(s, gdp, readl(gdp->regs + GAM_GDP_NVN_OFFSET)); + DBGFS_DUMP(GAM_GDP_KEY1); + DBGFS_DUMP(GAM_GDP_KEY2); + DBGFS_DUMP(GAM_GDP_PPT); + gdp_dbg_ppt(s, readl(gdp->regs + GAM_GDP_PPT_OFFSET)); + DBGFS_DUMP(GAM_GDP_CML); + DBGFS_DUMP(GAM_GDP_MST); + gdp_dbg_mst(s, readl(gdp->regs + GAM_GDP_MST_OFFSET)); + + seq_puts(s, "\n\n"); + if (!crtc) + seq_puts(s, " Not connected to any DRM CRTC\n"); + else + seq_printf(s, " Connected to DRM CRTC #%d (%s)\n", + crtc->base.id, sti_mixer_to_str(to_sti_mixer(crtc))); + + mutex_unlock(&dev->struct_mutex); + return 0; +} + +static void gdp_node_dump_node(struct seq_file *s, struct sti_gdp_node *node) +{ + seq_printf(s, "\t@:0x%p", node); + seq_printf(s, "\n\tCTL 0x%08X", node->gam_gdp_ctl); + gdp_dbg_ctl(s, node->gam_gdp_ctl); + seq_printf(s, "\n\tAGC 0x%08X", node->gam_gdp_agc); + seq_printf(s, "\n\tVPO 0x%08X", node->gam_gdp_vpo); + gdp_dbg_vpo(s, node->gam_gdp_vpo); + seq_printf(s, "\n\tVPS 0x%08X", node->gam_gdp_vps); + gdp_dbg_vps(s, node->gam_gdp_vps); + seq_printf(s, "\n\tPML 0x%08X", node->gam_gdp_pml); + seq_printf(s, "\n\tPMP 0x%08X", node->gam_gdp_pmp); + seq_printf(s, "\n\tSIZE 0x%08X", node->gam_gdp_size); + gdp_dbg_size(s, node->gam_gdp_size); + seq_printf(s, "\n\tNVN 0x%08X", node->gam_gdp_nvn); + seq_printf(s, "\n\tKEY1 0x%08X", node->gam_gdp_key1); + seq_printf(s, "\n\tKEY2 0x%08X", node->gam_gdp_key2); + seq_printf(s, "\n\tPPT 0x%08X", node->gam_gdp_ppt); + gdp_dbg_ppt(s, node->gam_gdp_ppt); + seq_printf(s, "\n\tCML 0x%08X", node->gam_gdp_cml); + seq_puts(s, "\n"); +} + +static int gdp_node_dbg_show(struct seq_file *s, void *arg) +{ + struct drm_info_node *node = s->private; + struct sti_gdp *gdp = (struct sti_gdp *)node->info_ent->data; + struct drm_device *dev = node->minor->dev; + unsigned int b; + int ret; + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; + + for (b = 0; b < GDP_NODE_NB_BANK; b++) { + seq_printf(s, "\n%s[%d].top", sti_plane_to_str(&gdp->plane), b); + gdp_node_dump_node(s, gdp->node_list[b].top_field); + seq_printf(s, "\n%s[%d].btm", sti_plane_to_str(&gdp->plane), b); + gdp_node_dump_node(s, gdp->node_list[b].btm_field); + } + + mutex_unlock(&dev->struct_mutex); + return 0; +} + +static struct drm_info_list gdp0_debugfs_files[] = { + { "gdp0", gdp_dbg_show, 0, NULL }, + { "gdp0_node", gdp_node_dbg_show, 0, NULL }, +}; + +static struct drm_info_list gdp1_debugfs_files[] = { + { "gdp1", gdp_dbg_show, 0, NULL }, + { "gdp1_node", gdp_node_dbg_show, 0, NULL }, +}; + +static struct drm_info_list gdp2_debugfs_files[] = { + { "gdp2", gdp_dbg_show, 0, NULL }, + { "gdp2_node", gdp_node_dbg_show, 0, NULL }, +}; + +static struct drm_info_list gdp3_debugfs_files[] = { + { "gdp3", gdp_dbg_show, 0, NULL }, + { "gdp3_node", gdp_node_dbg_show, 0, NULL }, +}; + +static int gdp_debugfs_init(struct sti_gdp *gdp, struct drm_minor *minor) +{ + unsigned int i; + struct drm_info_list *gdp_debugfs_files; + int nb_files; + + switch (gdp->plane.desc) { + case STI_GDP_0: + gdp_debugfs_files = gdp0_debugfs_files; + nb_files = ARRAY_SIZE(gdp0_debugfs_files); + break; + case STI_GDP_1: + gdp_debugfs_files = gdp1_debugfs_files; + nb_files = ARRAY_SIZE(gdp1_debugfs_files); + break; + case STI_GDP_2: + gdp_debugfs_files = gdp2_debugfs_files; + nb_files = ARRAY_SIZE(gdp2_debugfs_files); + break; + case STI_GDP_3: + gdp_debugfs_files = gdp3_debugfs_files; + nb_files = ARRAY_SIZE(gdp3_debugfs_files); + break; + default: + return -EINVAL; + } + + for (i = 0; i < nb_files; i++) + gdp_debugfs_files[i].data = gdp; + + return drm_debugfs_create_files(gdp_debugfs_files, + nb_files, + minor->debugfs_root, minor); +} + static int sti_gdp_fourcc2format(int fourcc) { switch (fourcc) { @@ -684,6 +917,9 @@ struct drm_plane *sti_gdp_create(struct drm_device *drm_dev,
sti_plane_init_property(&gdp->plane, type);
+ if (gdp_debugfs_init(gdp, drm_dev->primary)) + DRM_ERROR("GDP debugfs setup failed\n"); + return &gdp->plane.drm_plane;
err:
Signed-off-by: Vincent Abriou vincent.abriou@st.com --- drivers/gpu/drm/sti/sti_hqvdp.c | 243 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 243 insertions(+)
diff --git a/drivers/gpu/drm/sti/sti_hqvdp.c b/drivers/gpu/drm/sti/sti_hqvdp.c index eace56d..8d2118a 100644 --- a/drivers/gpu/drm/sti/sti_hqvdp.c +++ b/drivers/gpu/drm/sti/sti_hqvdp.c @@ -414,6 +414,246 @@ static int sti_hqvdp_get_curr_cmd(struct sti_hqvdp *hqvdp) }
/** + * sti_hqvdp_get_next_cmd + * @hqvdp: hqvdp structure + * + * Look for the next hqvdp_cmd that will be used by the FW. + * + * RETURNS: + * the offset of the next command that will be used. + * -1 in error cases + */ +static int sti_hqvdp_get_next_cmd(struct sti_hqvdp *hqvdp) +{ + int next_cmd; + dma_addr_t cmd = hqvdp->hqvdp_cmd_paddr; + unsigned int i; + + next_cmd = readl(hqvdp->regs + HQVDP_MBX_NEXT_CMD); + + for (i = 0; i < NB_VDP_CMD; i++) { + if (cmd == next_cmd) + return i * sizeof(struct sti_hqvdp_cmd); + + cmd += sizeof(struct sti_hqvdp_cmd); + } + + return -1; +} + +#define DBGFS_DUMP(reg) seq_printf(s, "\n %-25s 0x%08X", #reg, \ + readl(hqvdp->regs + reg)) + +static const char *hqvdp_dbg_get_lut(u32 *coef) +{ + if (!memcmp(coef, coef_lut_a_legacy, 16)) + return "LUT A"; + if (!memcmp(coef, coef_lut_b, 16)) + return "LUT B"; + if (!memcmp(coef, coef_lut_c_y_legacy, 16)) + return "LUT C Y"; + if (!memcmp(coef, coef_lut_c_c_legacy, 16)) + return "LUT C C"; + if (!memcmp(coef, coef_lut_d_y_legacy, 16)) + return "LUT D Y"; + if (!memcmp(coef, coef_lut_d_c_legacy, 16)) + return "LUT D C"; + if (!memcmp(coef, coef_lut_e_y_legacy, 16)) + return "LUT E Y"; + if (!memcmp(coef, coef_lut_e_c_legacy, 16)) + return "LUT E C"; + if (!memcmp(coef, coef_lut_f_y_legacy, 16)) + return "LUT F Y"; + if (!memcmp(coef, coef_lut_f_c_legacy, 16)) + return "LUT F C"; + return "<UNKNOWN>"; +} + +static void hqvdp_dbg_dump_cmd(struct seq_file *s, struct sti_hqvdp_cmd *c) +{ + int src_w, src_h, dst_w, dst_h; + + seq_puts(s, "\n\tTOP:"); + seq_printf(s, "\n\t %-20s 0x%08X", "Config", c->top.config); + switch (c->top.config) { + case TOP_CONFIG_PROGRESSIVE: + seq_puts(s, "\tProgressive"); + break; + case TOP_CONFIG_INTER_TOP: + seq_puts(s, "\tInterlaced, top field"); + break; + case TOP_CONFIG_INTER_BTM: + seq_puts(s, "\tInterlaced, bottom field"); + break; + default: + seq_puts(s, "\t<UNKNOWN>"); + break; + } + + seq_printf(s, "\n\t %-20s 0x%08X", "MemFormat", c->top.mem_format); + seq_printf(s, "\n\t %-20s 0x%08X", "CurrentY", c->top.current_luma); + seq_printf(s, "\n\t %-20s 0x%08X", "CurrentC", c->top.current_chroma); + seq_printf(s, "\n\t %-20s 0x%08X", "YSrcPitch", c->top.luma_src_pitch); + seq_printf(s, "\n\t %-20s 0x%08X", "CSrcPitch", + c->top.chroma_src_pitch); + seq_printf(s, "\n\t %-20s 0x%08X", "InputFrameSize", + c->top.input_frame_size); + seq_printf(s, "\t%dx%d", + c->top.input_frame_size & 0x0000FFFF, + c->top.input_frame_size >> 16); + seq_printf(s, "\n\t %-20s 0x%08X", "InputViewportSize", + c->top.input_viewport_size); + src_w = c->top.input_viewport_size & 0x0000FFFF; + src_h = c->top.input_viewport_size >> 16; + seq_printf(s, "\t%dx%d", src_w, src_h); + + seq_puts(s, "\n\tHVSRC:"); + seq_printf(s, "\n\t %-20s 0x%08X", "OutputPictureSize", + c->hvsrc.output_picture_size); + dst_w = c->hvsrc.output_picture_size & 0x0000FFFF; + dst_h = c->hvsrc.output_picture_size >> 16; + seq_printf(s, "\t%dx%d", dst_w, dst_h); + seq_printf(s, "\n\t %-20s 0x%08X", "ParamCtrl", c->hvsrc.param_ctrl); + + seq_printf(s, "\n\t %-20s %s", "yh_coef", + hqvdp_dbg_get_lut(c->hvsrc.yh_coef)); + seq_printf(s, "\n\t %-20s %s", "ch_coef", + hqvdp_dbg_get_lut(c->hvsrc.ch_coef)); + seq_printf(s, "\n\t %-20s %s", "yv_coef", + hqvdp_dbg_get_lut(c->hvsrc.yv_coef)); + seq_printf(s, "\n\t %-20s %s", "cv_coef", + hqvdp_dbg_get_lut(c->hvsrc.cv_coef)); + + seq_printf(s, "\n\t %-20s", "ScaleH"); + if (dst_w > src_w) + seq_printf(s, " %d/1", dst_w / src_w); + else + seq_printf(s, " 1/%d", src_w / dst_w); + + seq_printf(s, "\n\t %-20s", "tScaleV"); + if (dst_h > src_h) + seq_printf(s, " %d/1", dst_h / src_h); + else + seq_printf(s, " 1/%d", src_h / dst_h); + + seq_puts(s, "\n\tCSDI:"); + seq_printf(s, "\n\t %-20s 0x%08X\t", "Config", c->csdi.config); + switch (c->csdi.config) { + case CSDI_CONFIG_PROG: + seq_puts(s, "Bypass"); + break; + case CSDI_CONFIG_INTER_DIR: + seq_puts(s, "Deinterlace, directional"); + break; + default: + seq_puts(s, "<UNKNOWN>"); + break; + } + + seq_printf(s, "\n\t %-20s 0x%08X", "Config2", c->csdi.config2); + seq_printf(s, "\n\t %-20s 0x%08X", "DcdiConfig", c->csdi.dcdi_config); +} + +static int hqvdp_dbg_show(struct seq_file *s, void *data) +{ + struct drm_info_node *node = s->private; + struct sti_hqvdp *hqvdp = (struct sti_hqvdp *)node->info_ent->data; + struct drm_device *dev = node->minor->dev; + int cmd, cmd_offset, infoxp70; + void *virt; + int ret; + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; + + seq_printf(s, "%s: (vaddr = 0x%p)", + sti_plane_to_str(&hqvdp->plane), hqvdp->regs); + + DBGFS_DUMP(HQVDP_MBX_IRQ_TO_XP70); + DBGFS_DUMP(HQVDP_MBX_INFO_HOST); + DBGFS_DUMP(HQVDP_MBX_IRQ_TO_HOST); + DBGFS_DUMP(HQVDP_MBX_INFO_XP70); + infoxp70 = readl(hqvdp->regs + HQVDP_MBX_INFO_XP70); + seq_puts(s, "\tFirmware state: "); + if (infoxp70 & INFO_XP70_FW_READY) + seq_puts(s, "idle and ready"); + else if (infoxp70 & INFO_XP70_FW_PROCESSING) + seq_puts(s, "processing a picture"); + else if (infoxp70 & INFO_XP70_FW_INITQUEUES) + seq_puts(s, "programming queues"); + else + seq_puts(s, "NOT READY"); + + DBGFS_DUMP(HQVDP_MBX_SW_RESET_CTRL); + DBGFS_DUMP(HQVDP_MBX_STARTUP_CTRL1); + if (readl(hqvdp->regs + HQVDP_MBX_STARTUP_CTRL1) + & STARTUP_CTRL1_RST_DONE) + seq_puts(s, "\tReset is done"); + else + seq_puts(s, "\tReset is NOT done"); + DBGFS_DUMP(HQVDP_MBX_STARTUP_CTRL2); + if (readl(hqvdp->regs + HQVDP_MBX_STARTUP_CTRL2) + & STARTUP_CTRL2_FETCH_EN) + seq_puts(s, "\tFetch is enabled"); + else + seq_puts(s, "\tFetch is NOT enabled"); + DBGFS_DUMP(HQVDP_MBX_GP_STATUS); + DBGFS_DUMP(HQVDP_MBX_NEXT_CMD); + DBGFS_DUMP(HQVDP_MBX_CURRENT_CMD); + DBGFS_DUMP(HQVDP_MBX_SOFT_VSYNC); + if (!(readl(hqvdp->regs + HQVDP_MBX_SOFT_VSYNC) & 3)) + seq_puts(s, "\tHW Vsync"); + else + seq_puts(s, "\tSW Vsync ?!?!"); + + /* Last command */ + cmd = readl(hqvdp->regs + HQVDP_MBX_CURRENT_CMD); + cmd_offset = sti_hqvdp_get_curr_cmd(hqvdp); + if (cmd_offset == -1) { + seq_puts(s, "\n\n Last command: unknown"); + } else { + virt = hqvdp->hqvdp_cmd + cmd_offset; + seq_printf(s, "\n\n Last command: address @ 0x%x (0x%p)", + cmd, virt); + hqvdp_dbg_dump_cmd(s, (struct sti_hqvdp_cmd *)virt); + } + + /* Next command */ + cmd = readl(hqvdp->regs + HQVDP_MBX_NEXT_CMD); + cmd_offset = sti_hqvdp_get_next_cmd(hqvdp); + if (cmd_offset == -1) { + seq_puts(s, "\n\n Next command: unknown"); + } else { + virt = hqvdp->hqvdp_cmd + cmd_offset; + seq_printf(s, "\n\n Next command address: @ 0x%x (0x%p)", + cmd, virt); + hqvdp_dbg_dump_cmd(s, (struct sti_hqvdp_cmd *)virt); + } + + seq_puts(s, "\n"); + + mutex_unlock(&dev->struct_mutex); + return 0; +} + +static struct drm_info_list hqvdp_debugfs_files[] = { + { "hqvdp", hqvdp_dbg_show, 0, NULL }, +}; + +static int hqvdp_debugfs_init(struct sti_hqvdp *hqvdp, struct drm_minor *minor) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(hqvdp_debugfs_files); i++) + hqvdp_debugfs_files[i].data = hqvdp; + + return drm_debugfs_create_files(hqvdp_debugfs_files, + ARRAY_SIZE(hqvdp_debugfs_files), + minor->debugfs_root, minor); +} + +/** * sti_hqvdp_update_hvsrc * @orient: horizontal or vertical * @scale: scaling/zoom factor @@ -1026,6 +1266,9 @@ static struct drm_plane *sti_hqvdp_create(struct drm_device *drm_dev,
sti_plane_init_property(&hqvdp->plane, DRM_PLANE_TYPE_OVERLAY);
+ if (hqvdp_debugfs_init(hqvdp, drm_dev->primary)) + DRM_ERROR("HQVDP debugfs setup failed\n"); + return &hqvdp->plane.drm_plane; }
Signed-off-by: Vincent Abriou vincent.abriou@st.com --- drivers/gpu/drm/sti/sti_compositor.c | 2 +- drivers/gpu/drm/sti/sti_vid.c | 94 +++++++++++++++++++++++++++++++++++- drivers/gpu/drm/sti/sti_vid.h | 4 +- 3 files changed, 95 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/sti/sti_compositor.c b/drivers/gpu/drm/sti/sti_compositor.c index afed217..5b827a9 100644 --- a/drivers/gpu/drm/sti/sti_compositor.c +++ b/drivers/gpu/drm/sti/sti_compositor.c @@ -75,7 +75,7 @@ static int sti_compositor_bind(struct device *dev, switch (desc[i].type) { case STI_VID_SUBDEV: compo->vid[vid_id++] = - sti_vid_create(compo->dev, desc[i].id, + sti_vid_create(compo->dev, drm_dev, desc[i].id, compo->regs + desc[i].offset); break; case STI_MIXER_MAIN_SUBDEV: diff --git a/drivers/gpu/drm/sti/sti_vid.c b/drivers/gpu/drm/sti/sti_vid.c index 0a1e50c..5a2c5dc 100644 --- a/drivers/gpu/drm/sti/sti_vid.c +++ b/drivers/gpu/drm/sti/sti_vid.c @@ -54,6 +54,93 @@
#define VID_MIN_HD_HEIGHT 720
+#define DBGFS_DUMP(reg) seq_printf(s, "\n %-25s 0x%08X", #reg, \ + readl(vid->regs + reg)) + +static void vid_dbg_ctl(struct seq_file *s, int val) +{ + val = val >> 30; + seq_puts(s, "\t"); + + if (!(val & 1)) + seq_puts(s, "NOT "); + seq_puts(s, "ignored on main mixer - "); + + if (!(val & 2)) + seq_puts(s, "NOT "); + seq_puts(s, "ignored on aux mixer"); +} + +static void vid_dbg_vpo(struct seq_file *s, int val) +{ + seq_printf(s, "\txdo:%4d\tydo:%4d", val & 0x0FFF, (val >> 16) & 0x0FFF); +} + +static void vid_dbg_vps(struct seq_file *s, int val) +{ + seq_printf(s, "\txds:%4d\tyds:%4d", val & 0x0FFF, (val >> 16) & 0x0FFF); +} + +static void vid_dbg_mst(struct seq_file *s, int val) +{ + if (val & 1) + seq_puts(s, "\tBUFFER UNDERFLOW!"); +} + +static int vid_dbg_show(struct seq_file *s, void *arg) +{ + struct drm_info_node *node = s->private; + struct sti_vid *vid = (struct sti_vid *)node->info_ent->data; + struct drm_device *dev = node->minor->dev; + int ret; + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; + + seq_printf(s, "VID: (vaddr= 0x%p)", vid->regs); + + DBGFS_DUMP(VID_CTL); + vid_dbg_ctl(s, readl(vid->regs + VID_CTL)); + DBGFS_DUMP(VID_ALP); + DBGFS_DUMP(VID_CLF); + DBGFS_DUMP(VID_VPO); + vid_dbg_vpo(s, readl(vid->regs + VID_VPO)); + DBGFS_DUMP(VID_VPS); + vid_dbg_vps(s, readl(vid->regs + VID_VPS)); + DBGFS_DUMP(VID_KEY1); + DBGFS_DUMP(VID_KEY2); + DBGFS_DUMP(VID_MPR0); + DBGFS_DUMP(VID_MPR1); + DBGFS_DUMP(VID_MPR2); + DBGFS_DUMP(VID_MPR3); + DBGFS_DUMP(VID_MST); + vid_dbg_mst(s, readl(vid->regs + VID_MST)); + DBGFS_DUMP(VID_BC); + DBGFS_DUMP(VID_TINT); + DBGFS_DUMP(VID_CSAT); + seq_puts(s, "\n"); + + mutex_unlock(&dev->struct_mutex); + return 0; +} + +static struct drm_info_list vid_debugfs_files[] = { + { "vid", vid_dbg_show, 0, NULL }, +}; + +static int vid_debugfs_init(struct sti_vid *vid, struct drm_minor *minor) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(vid_debugfs_files); i++) + vid_debugfs_files[i].data = vid; + + return drm_debugfs_create_files(vid_debugfs_files, + ARRAY_SIZE(vid_debugfs_files), + minor->debugfs_root, minor); +} + void sti_vid_commit(struct sti_vid *vid, struct drm_plane_state *state) { @@ -122,8 +209,8 @@ static void sti_vid_init(struct sti_vid *vid) writel(VID_CSAT_DFLT, vid->regs + VID_CSAT); }
-struct sti_vid *sti_vid_create(struct device *dev, int id, - void __iomem *baseaddr) +struct sti_vid *sti_vid_create(struct device *dev, struct drm_device *drm_dev, + int id, void __iomem *baseaddr) { struct sti_vid *vid;
@@ -139,5 +226,8 @@ struct sti_vid *sti_vid_create(struct device *dev, int id,
sti_vid_init(vid);
+ if (vid_debugfs_init(vid, drm_dev->primary)) + DRM_ERROR("VID debugfs setup failed\n"); + return vid; } diff --git a/drivers/gpu/drm/sti/sti_vid.h b/drivers/gpu/drm/sti/sti_vid.h index 5dea479..6c84234 100644 --- a/drivers/gpu/drm/sti/sti_vid.h +++ b/drivers/gpu/drm/sti/sti_vid.h @@ -23,7 +23,7 @@ struct sti_vid { void sti_vid_commit(struct sti_vid *vid, struct drm_plane_state *state); void sti_vid_disable(struct sti_vid *vid); -struct sti_vid *sti_vid_create(struct device *dev, int id, - void __iomem *baseaddr); +struct sti_vid *sti_vid_create(struct device *dev, struct drm_device *drm_dev, + int id, void __iomem *baseaddr);
#endif
Signed-off-by: Vincent Abriou vincent.abriou@st.com --- drivers/gpu/drm/sti/sti_compositor.c | 2 +- drivers/gpu/drm/sti/sti_mixer.c | 146 ++++++++++++++++++++++++++++++++++- drivers/gpu/drm/sti/sti_mixer.h | 4 +- 3 files changed, 149 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/sti/sti_compositor.c b/drivers/gpu/drm/sti/sti_compositor.c index 5b827a9..3d2fa3a 100644 --- a/drivers/gpu/drm/sti/sti_compositor.c +++ b/drivers/gpu/drm/sti/sti_compositor.c @@ -81,7 +81,7 @@ static int sti_compositor_bind(struct device *dev, case STI_MIXER_MAIN_SUBDEV: case STI_MIXER_AUX_SUBDEV: compo->mixer[mixer_id++] = - sti_mixer_create(compo->dev, desc[i].id, + sti_mixer_create(compo->dev, drm_dev, desc[i].id, compo->regs + desc[i].offset); break; case STI_GPD_SUBDEV: diff --git a/drivers/gpu/drm/sti/sti_mixer.c b/drivers/gpu/drm/sti/sti_mixer.c index 49db835..e7425c3 100644 --- a/drivers/gpu/drm/sti/sti_mixer.c +++ b/drivers/gpu/drm/sti/sti_mixer.c @@ -75,6 +75,145 @@ static inline void sti_mixer_reg_write(struct sti_mixer *mixer, writel(val, mixer->regs + reg_id); }
+#define DBGFS_DUMP(reg) seq_printf(s, "\n %-25s 0x%08X", #reg, \ + sti_mixer_reg_read(mixer, reg)) + +static void mixer_dbg_ctl(struct seq_file *s, int val) +{ + unsigned int i; + int count = 0; + char *const disp_layer[] = {"BKG", "VID0", "VID1", "GDP0", + "GDP1", "GDP2", "GDP3"}; + + seq_puts(s, "\tEnabled: "); + for (i = 0; i < 7; i++) { + if (val & 1) { + seq_printf(s, "%s ", disp_layer[i]); + count++; + } + val = val >> 1; + } + + val = val >> 2; + if (val & 1) { + seq_puts(s, "CURS "); + count++; + } + if (!count) + seq_puts(s, "Nothing"); +} + +static void mixer_dbg_crb(struct seq_file *s, int val) +{ + int i; + + seq_puts(s, "\tDepth: "); + for (i = 0; i < GAM_MIXER_NB_DEPTH_LEVEL; i++) { + switch (val & GAM_DEPTH_MASK_ID) { + case GAM_DEPTH_VID0_ID: + seq_puts(s, "VID0"); + break; + case GAM_DEPTH_VID1_ID: + seq_puts(s, "VID1"); + break; + case GAM_DEPTH_GDP0_ID: + seq_puts(s, "GDP0"); + break; + case GAM_DEPTH_GDP1_ID: + seq_puts(s, "GDP1"); + break; + case GAM_DEPTH_GDP2_ID: + seq_puts(s, "GDP2"); + break; + case GAM_DEPTH_GDP3_ID: + seq_puts(s, "GDP3"); + break; + default: + seq_puts(s, "---"); + } + + if (i < GAM_MIXER_NB_DEPTH_LEVEL - 1) + seq_puts(s, " < "); + val = val >> 3; + } +} + +static void mixer_dbg_mxn(struct seq_file *s, void *addr) +{ + int i; + + for (i = 1; i < 8; i++) + seq_printf(s, "-0x%08X", (int)readl(addr + i * 4)); +} + +static int mixer_dbg_show(struct seq_file *s, void *arg) +{ + struct drm_info_node *node = s->private; + struct sti_mixer *mixer = (struct sti_mixer *)node->info_ent->data; + struct drm_device *dev = node->minor->dev; + int ret; + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; + + seq_printf(s, "%s: (vaddr = 0x%p)", + sti_mixer_to_str(mixer), mixer->regs); + + DBGFS_DUMP(GAM_MIXER_CTL); + mixer_dbg_ctl(s, sti_mixer_reg_read(mixer, GAM_MIXER_CTL)); + DBGFS_DUMP(GAM_MIXER_BKC); + DBGFS_DUMP(GAM_MIXER_BCO); + DBGFS_DUMP(GAM_MIXER_BCS); + DBGFS_DUMP(GAM_MIXER_AVO); + DBGFS_DUMP(GAM_MIXER_AVS); + DBGFS_DUMP(GAM_MIXER_CRB); + mixer_dbg_crb(s, sti_mixer_reg_read(mixer, GAM_MIXER_CRB)); + DBGFS_DUMP(GAM_MIXER_ACT); + DBGFS_DUMP(GAM_MIXER_MBP); + DBGFS_DUMP(GAM_MIXER_MX0); + mixer_dbg_mxn(s, mixer->regs + GAM_MIXER_MX0); + seq_puts(s, "\n"); + + mutex_unlock(&dev->struct_mutex); + return 0; +} + +static struct drm_info_list mixer0_debugfs_files[] = { + { "mixer_main", mixer_dbg_show, 0, NULL }, +}; + +static struct drm_info_list mixer1_debugfs_files[] = { + { "mixer_aux", mixer_dbg_show, 0, NULL }, +}; + +static int mixer_debugfs_init(struct sti_mixer *mixer, struct drm_minor *minor) +{ + unsigned int i; + struct drm_info_list *mixer_debugfs_files; + int nb_files; + + switch (mixer->id) { + case STI_MIXER_MAIN: + mixer_debugfs_files = mixer0_debugfs_files; + nb_files = ARRAY_SIZE(mixer0_debugfs_files); + break; + case STI_MIXER_AUX: + mixer_debugfs_files = mixer1_debugfs_files; + nb_files = ARRAY_SIZE(mixer1_debugfs_files); + break; + default: + return -EINVAL; + } + + for (i = 0; i < nb_files; i++) + mixer_debugfs_files[i].data = mixer; + + return drm_debugfs_create_files(mixer_debugfs_files, + nb_files, + minor->debugfs_root, minor); +} + void sti_mixer_set_background_status(struct sti_mixer *mixer, bool enable) { u32 val = sti_mixer_reg_read(mixer, GAM_MIXER_CTL); @@ -237,7 +376,9 @@ void sti_mixer_set_matrix(struct sti_mixer *mixer) mixerColorSpaceMatIdentity[i]); }
-struct sti_mixer *sti_mixer_create(struct device *dev, int id, +struct sti_mixer *sti_mixer_create(struct device *dev, + struct drm_device *drm_dev, + int id, void __iomem *baseaddr) { struct sti_mixer *mixer = devm_kzalloc(dev, sizeof(*mixer), GFP_KERNEL); @@ -258,5 +399,8 @@ struct sti_mixer *sti_mixer_create(struct device *dev, int id, DRM_DEBUG_DRIVER("%s created. Regs=%p\n", sti_mixer_to_str(mixer), mixer->regs);
+ if (mixer_debugfs_init(mixer, drm_dev->primary)) + DRM_ERROR("MIXER debugfs setup failed\n"); + return mixer; } diff --git a/drivers/gpu/drm/sti/sti_mixer.h b/drivers/gpu/drm/sti/sti_mixer.h index efb1a9a..6f35fc0 100644 --- a/drivers/gpu/drm/sti/sti_mixer.h +++ b/drivers/gpu/drm/sti/sti_mixer.h @@ -42,7 +42,9 @@ struct sti_mixer {
const char *sti_mixer_to_str(struct sti_mixer *mixer);
-struct sti_mixer *sti_mixer_create(struct device *dev, int id, +struct sti_mixer *sti_mixer_create(struct device *dev, + struct drm_device *drm_dev, + int id, void __iomem *baseaddr);
int sti_mixer_set_plane_status(struct sti_mixer *mixer,
Signed-off-by: Vincent Abriou vincent.abriou@st.com --- drivers/gpu/drm/sti/sti_tvout.c | 157 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+)
diff --git a/drivers/gpu/drm/sti/sti_tvout.c b/drivers/gpu/drm/sti/sti_tvout.c index 0b171fd..d4bb953 100644 --- a/drivers/gpu/drm/sti/sti_tvout.c +++ b/drivers/gpu/drm/sti/sti_tvout.c @@ -462,6 +462,157 @@ static void tvout_hda_start(struct sti_tvout *tvout, bool main_path) tvout_write(tvout, 0, TVO_HD_DAC_CFG_OFF); }
+#define DBGFS_DUMP(reg) seq_printf(s, "\n %-25s 0x%08X", #reg, \ + readl(tvout->regs + reg)) + +static void tvout_dbg_vip(struct seq_file *s, int val) +{ + int r, g, b, tmp, mask; + char *const reorder[] = {"Y_G", "Cb_B", "Cr_R"}; + char *const clipping[] = {"No", "EAV/SAV", "Limited range RGB/Y", + "Limited range Cb/Cr", "decided by register"}; + char *const round[] = {"8-bit", "10-bit", "12-bit"}; + char *const input_sel[] = {"Main (color matrix enabled)", + "Main (color matrix by-passed)", + "", "", "", "", "", "", + "Aux (color matrix enabled)", + "Aux (color matrix by-passed)", + "", "", "", "", "", "Force value"}; + + seq_puts(s, "\t"); + mask = TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_R_SHIFT; + r = (val & mask) >> TVO_VIP_REORDER_R_SHIFT; + mask = TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_G_SHIFT; + g = (val & mask) >> TVO_VIP_REORDER_G_SHIFT; + mask = TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_B_SHIFT; + b = (val & mask) >> TVO_VIP_REORDER_B_SHIFT; + seq_printf(s, "%-24s %s->%s %s->%s %s->%s\n", "Reorder:", + reorder[r], reorder[TVO_VIP_REORDER_CR_R_SEL], + reorder[g], reorder[TVO_VIP_REORDER_Y_G_SEL], + reorder[b], reorder[TVO_VIP_REORDER_CB_B_SEL]); + seq_puts(s, "\t\t\t\t\t"); + mask = TVO_VIP_CLIP_MASK << TVO_VIP_CLIP_SHIFT; + tmp = (val & mask) >> TVO_VIP_CLIP_SHIFT; + seq_printf(s, "%-24s %s\n", "Clipping:", clipping[tmp]); + seq_puts(s, "\t\t\t\t\t"); + mask = TVO_VIP_RND_MASK << TVO_VIP_RND_SHIFT; + tmp = (val & mask) >> TVO_VIP_RND_SHIFT; + seq_printf(s, "%-24s input data rounded to %s per component\n", + "Round:", round[tmp]); + seq_puts(s, "\t\t\t\t\t"); + tmp = (val & TVO_VIP_SEL_INPUT_MASK); + seq_printf(s, "%-24s %s", "Input selection:", input_sel[tmp]); +} + +static void tvout_dbg_hd_dac_cfg(struct seq_file *s, int val) +{ + seq_printf(s, "\t%-24s %s", "HD DAC:", + val & 1 ? "disabled" : "enabled"); +} + +static int tvout_dbg_show(struct seq_file *s, void *data) +{ + struct drm_info_node *node = s->private; + struct sti_tvout *tvout = (struct sti_tvout *)node->info_ent->data; + struct drm_device *dev = node->minor->dev; + struct drm_crtc *crtc; + int ret; + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; + + seq_printf(s, "TVOUT: (vaddr = 0x%p)", tvout->regs); + + seq_puts(s, "\n\n HDMI encoder: "); + crtc = tvout->hdmi->crtc; + if (crtc) { + seq_printf(s, "connected to %s path", + sti_crtc_is_main(crtc) ? "main" : "aux"); + DBGFS_DUMP(TVO_HDMI_SYNC_SEL); + DBGFS_DUMP(TVO_VIP_HDMI); + tvout_dbg_vip(s, readl(tvout->regs + TVO_VIP_HDMI)); + } else { + seq_puts(s, "disabled"); + } + + seq_puts(s, "\n\n DVO encoder: "); + crtc = tvout->dvo->crtc; + if (crtc) { + seq_printf(s, "connected to %s path", + sti_crtc_is_main(crtc) ? "main" : "aux"); + DBGFS_DUMP(TVO_DVO_SYNC_SEL); + DBGFS_DUMP(TVO_DVO_CONFIG); + DBGFS_DUMP(TVO_VIP_DVO); + tvout_dbg_vip(s, readl(tvout->regs + TVO_VIP_DVO)); + } else { + seq_puts(s, "disabled"); + } + + seq_puts(s, "\n\n HDA encoder: "); + crtc = tvout->hda->crtc; + if (crtc) { + seq_printf(s, "connected to %s path", + sti_crtc_is_main(crtc) ? "main" : "aux"); + DBGFS_DUMP(TVO_HD_SYNC_SEL); + DBGFS_DUMP(TVO_HD_DAC_CFG_OFF); + tvout_dbg_hd_dac_cfg(s, + readl(tvout->regs + TVO_HD_DAC_CFG_OFF)); + DBGFS_DUMP(TVO_VIP_HDF); + tvout_dbg_vip(s, readl(tvout->regs + TVO_VIP_HDF)); + } else { + seq_puts(s, "disabled"); + } + + seq_puts(s, "\n\n main path configuration"); + DBGFS_DUMP(TVO_CSC_MAIN_M0); + DBGFS_DUMP(TVO_CSC_MAIN_M1); + DBGFS_DUMP(TVO_CSC_MAIN_M2); + DBGFS_DUMP(TVO_CSC_MAIN_M3); + DBGFS_DUMP(TVO_CSC_MAIN_M4); + DBGFS_DUMP(TVO_CSC_MAIN_M5); + DBGFS_DUMP(TVO_CSC_MAIN_M6); + DBGFS_DUMP(TVO_CSC_MAIN_M7); + DBGFS_DUMP(TVO_MAIN_IN_VID_FORMAT); + + seq_puts(s, "\n\n auxiliary path configuration"); + DBGFS_DUMP(TVO_CSC_AUX_M0); + DBGFS_DUMP(TVO_CSC_AUX_M2); + DBGFS_DUMP(TVO_CSC_AUX_M3); + DBGFS_DUMP(TVO_CSC_AUX_M4); + DBGFS_DUMP(TVO_CSC_AUX_M5); + DBGFS_DUMP(TVO_CSC_AUX_M6); + DBGFS_DUMP(TVO_CSC_AUX_M7); + DBGFS_DUMP(TVO_AUX_IN_VID_FORMAT); + seq_puts(s, "\n"); + + mutex_unlock(&dev->struct_mutex); + return 0; +} + +static struct drm_info_list tvout_debugfs_files[] = { + { "tvout", tvout_dbg_show, 0, NULL }, +}; + +static void tvout_debugfs_exit(struct sti_tvout *tvout, struct drm_minor *minor) +{ + drm_debugfs_remove_files(tvout_debugfs_files, + ARRAY_SIZE(tvout_debugfs_files), + minor); +} + +static int tvout_debugfs_init(struct sti_tvout *tvout, struct drm_minor *minor) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(tvout_debugfs_files); i++) + tvout_debugfs_files[i].data = tvout; + + return drm_debugfs_create_files(tvout_debugfs_files, + ARRAY_SIZE(tvout_debugfs_files), + minor->debugfs_root, minor); +} + static void sti_tvout_encoder_dpms(struct drm_encoder *encoder, int mode) { } @@ -678,6 +829,9 @@ static int sti_tvout_bind(struct device *dev, struct device *master, void *data)
sti_tvout_create_encoders(drm_dev, tvout);
+ if (tvout_debugfs_init(tvout, drm_dev->primary)) + DRM_ERROR("TVOUT debugfs setup failed\n"); + return 0; }
@@ -685,8 +839,11 @@ static void sti_tvout_unbind(struct device *dev, struct device *master, void *data) { struct sti_tvout *tvout = dev_get_drvdata(dev); + struct drm_device *drm_dev = data;
sti_tvout_destroy_encoders(tvout); + + tvout_debugfs_exit(tvout, drm_dev->primary); }
static const struct component_ops sti_tvout_ops = {
Display fps on demand for each used plane: cat /sys/kernel/debug/dri/0/fps_get Display fps in live in the console for each used plane: echo 255 > /sys/kernel/debug/dri/0/fps_show
Signed-off-by: Vincent Abriou vincent.abriou@st.com --- drivers/gpu/drm/sti/sti_cursor.c | 2 + drivers/gpu/drm/sti/sti_drv.c | 128 +++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/sti/sti_gdp.c | 2 + drivers/gpu/drm/sti/sti_hqvdp.c | 11 ++-- drivers/gpu/drm/sti/sti_plane.c | 63 +++++++++++++++++++ drivers/gpu/drm/sti/sti_plane.h | 17 ++++++ 6 files changed, 216 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/sti/sti_cursor.c b/drivers/gpu/drm/sti/sti_cursor.c index 9eac1b9..82b5711 100644 --- a/drivers/gpu/drm/sti/sti_cursor.c +++ b/drivers/gpu/drm/sti/sti_cursor.c @@ -306,6 +306,8 @@ static void sti_cursor_atomic_update(struct drm_plane *drm_plane, writel(cursor->clut_paddr, cursor->regs + CUR_CML); writel(CUR_CTL_CLUT_UPDATE, cursor->regs + CUR_CTL);
+ sti_plane_update_fps(plane, true, false); + plane->status = STI_PLANE_UPDATED; }
diff --git a/drivers/gpu/drm/sti/sti_drv.c b/drivers/gpu/drm/sti/sti_drv.c index bcb1861..e5ef6b6 100644 --- a/drivers/gpu/drm/sti/sti_drv.c +++ b/drivers/gpu/drm/sti/sti_drv.c @@ -20,6 +20,7 @@
#include "sti_crtc.h" #include "sti_drv.h" +#include "sti_plane.h"
#define DRIVER_NAME "sti" #define DRIVER_DESC "STMicroelectronics SoC DRM" @@ -30,6 +31,130 @@ #define STI_MAX_FB_HEIGHT 4096 #define STI_MAX_FB_WIDTH 4096
+static int sti_drm_fps_get(void *data, u64 *val) +{ + struct drm_device *drm_dev = data; + struct drm_plane *p; + unsigned int i = 0; + + *val = 0; + list_for_each_entry(p, &drm_dev->mode_config.plane_list, head) { + struct sti_plane *plane = to_sti_plane(p); + + *val |= plane->fps_info.output << i; + i++; + } + + return 0; +} + +static int sti_drm_fps_set(void *data, u64 val) +{ + struct drm_device *drm_dev = data; + struct drm_plane *p; + unsigned int i = 0; + + list_for_each_entry(p, &drm_dev->mode_config.plane_list, head) { + struct sti_plane *plane = to_sti_plane(p); + + plane->fps_info.output = (val >> i) & 1; + i++; + } + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(sti_drm_fps_fops, + sti_drm_fps_get, sti_drm_fps_set, "%llu\n"); + +static int sti_drm_fps_dbg_show(struct seq_file *s, void *data) +{ + struct drm_info_node *node = s->private; + struct drm_device *dev = node->minor->dev; + struct drm_plane *p; + int ret; + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; + + list_for_each_entry(p, &dev->mode_config.plane_list, head) { + struct sti_plane *plane = to_sti_plane(p); + + seq_printf(s, "%s%s\n", + plane->fps_info.fps_str, + plane->fps_info.fips_str); + } + + mutex_unlock(&dev->struct_mutex); + return 0; +} + +static struct drm_info_list sti_drm_dbg_list[] = { + {"fps_get", sti_drm_fps_dbg_show, 0}, +}; + +static int sti_drm_debugfs_create(struct dentry *root, + struct drm_minor *minor, + const char *name, + const struct file_operations *fops) +{ + struct drm_device *dev = minor->dev; + struct drm_info_node *node; + struct dentry *ent; + + ent = debugfs_create_file(name, S_IRUGO | S_IWUSR, root, dev, fops); + if (IS_ERR(ent)) + return PTR_ERR(ent); + + node = kmalloc(sizeof(*node), GFP_KERNEL); + if (!node) { + debugfs_remove(ent); + return -ENOMEM; + } + + node->minor = minor; + node->dent = ent; + node->info_ent = (void *)fops; + + mutex_lock(&minor->debugfs_lock); + list_add(&node->list, &minor->debugfs_list); + mutex_unlock(&minor->debugfs_lock); + + return 0; +} + +static int sti_drm_dbg_init(struct drm_minor *minor) +{ + int ret; + + ret = drm_debugfs_create_files(sti_drm_dbg_list, + ARRAY_SIZE(sti_drm_dbg_list), + minor->debugfs_root, minor); + if (ret) + goto err; + + ret = sti_drm_debugfs_create(minor->debugfs_root, minor, "fps_show", + &sti_drm_fps_fops); + if (ret) + goto err; + + DRM_INFO("%s: debugfs installed\n", DRIVER_NAME); + return 0; +err: + DRM_ERROR("%s: cannot install debugfs\n", DRIVER_NAME); + return ret; +} + +void sti_drm_dbg_cleanup(struct drm_minor *minor) +{ + drm_debugfs_remove_files(sti_drm_dbg_list, + ARRAY_SIZE(sti_drm_dbg_list), minor); + + drm_debugfs_remove_files((struct drm_info_list *)&sti_drm_fps_fops, + 1, minor); +} + static void sti_atomic_schedule(struct sti_private *private, struct drm_atomic_state *state) { @@ -215,6 +340,9 @@ static struct drm_driver sti_driver = { .gem_prime_vunmap = drm_gem_cma_prime_vunmap, .gem_prime_mmap = drm_gem_cma_prime_mmap,
+ .debugfs_init = sti_drm_dbg_init, + .debugfs_cleanup = sti_drm_dbg_cleanup, + .name = DRIVER_NAME, .desc = DRIVER_DESC, .date = DRIVER_DATE, diff --git a/drivers/gpu/drm/sti/sti_gdp.c b/drivers/gpu/drm/sti/sti_gdp.c index 8f0e89f..67f606a 100644 --- a/drivers/gpu/drm/sti/sti_gdp.c +++ b/drivers/gpu/drm/sti/sti_gdp.c @@ -850,6 +850,8 @@ static void sti_gdp_atomic_update(struct drm_plane *drm_plane, }
end: + sti_plane_update_fps(plane, true, false); + plane->status = STI_PLANE_UPDATED; }
diff --git a/drivers/gpu/drm/sti/sti_hqvdp.c b/drivers/gpu/drm/sti/sti_hqvdp.c index 8d2118a..e9c33fb 100644 --- a/drivers/gpu/drm/sti/sti_hqvdp.c +++ b/drivers/gpu/drm/sti/sti_hqvdp.c @@ -326,8 +326,6 @@ struct sti_hqvdp_cmd { * @reset: reset control * @vtg_nb: notifier to handle VTG Vsync * @btm_field_pending: is there any bottom field (interlaced frame) to display - * @curr_field_count: number of field updates - * @last_field_count: number of field updates since last fps measure * @hqvdp_cmd: buffer of commands * @hqvdp_cmd_paddr: physical address of hqvdp_cmd * @vtg: vtg for main data path @@ -343,8 +341,6 @@ struct sti_hqvdp { struct reset_control *reset; struct notifier_block vtg_nb; bool btm_field_pending; - unsigned int curr_field_count; - unsigned int last_field_count; void *hqvdp_cmd; dma_addr_t hqvdp_cmd_paddr; struct sti_vtg *vtg; @@ -836,11 +832,12 @@ int sti_hqvdp_vtg_cb(struct notifier_block *nb, unsigned long evt, void *data) writel(hqvdp->hqvdp_cmd_paddr + btm_cmd_offset, hqvdp->regs + HQVDP_MBX_NEXT_CMD);
- hqvdp->curr_field_count++; hqvdp->btm_field_pending = false;
dev_dbg(hqvdp->dev, "%s Posted command:0x%x\n", __func__, hqvdp->hqvdp_cmd_paddr); + + sti_plane_update_fps(&hqvdp->plane, false, true); }
return 0; @@ -1204,8 +1201,6 @@ static void sti_hqvdp_atomic_update(struct drm_plane *drm_plane, writel(hqvdp->hqvdp_cmd_paddr + cmd_offset, hqvdp->regs + HQVDP_MBX_NEXT_CMD);
- hqvdp->curr_field_count++; - /* Interlaced : get ready to display the bottom field at next Vsync */ if (fb->flags & DRM_MODE_FB_INTERLACED) hqvdp->btm_field_pending = true; @@ -1213,6 +1208,8 @@ static void sti_hqvdp_atomic_update(struct drm_plane *drm_plane, dev_dbg(hqvdp->dev, "%s Posted command:0x%x\n", __func__, hqvdp->hqvdp_cmd_paddr + cmd_offset);
+ sti_plane_update_fps(plane, true, true); + plane->status = STI_PLANE_UPDATED; }
diff --git a/drivers/gpu/drm/sti/sti_plane.c b/drivers/gpu/drm/sti/sti_plane.c index 2e5c751..f10c98d 100644 --- a/drivers/gpu/drm/sti/sti_plane.c +++ b/drivers/gpu/drm/sti/sti_plane.c @@ -43,6 +43,69 @@ const char *sti_plane_to_str(struct sti_plane *plane) } }
+#define STI_FPS_INTERVAL_MS 3000 + +static int sti_plane_timespec_ms_diff(struct timespec lhs, struct timespec rhs) +{ + struct timespec tmp_ts = timespec_sub(lhs, rhs); + u64 tmp_ns = (u64)timespec_to_ns(&tmp_ts); + + do_div(tmp_ns, NSEC_PER_MSEC); + + return (u32)tmp_ns; +} + +void sti_plane_update_fps(struct sti_plane *plane, + bool new_frame, + bool new_field) +{ + struct timespec now; + struct sti_fps_info *fps; + int fpks, fipks, ms_since_last, num_frames, num_fields; + + getrawmonotonic(&now); + + /* Compute number of frame updates */ + fps = &plane->fps_info; + + if (new_field) + fps->curr_field_counter++; + + /* do not perform fps calcul if new_frame is false */ + if (!new_frame) + return; + + fps->curr_frame_counter++; + ms_since_last = sti_plane_timespec_ms_diff(now, fps->last_timestamp); + num_frames = fps->curr_frame_counter - fps->last_frame_counter; + + if (num_frames <= 0 || ms_since_last < STI_FPS_INTERVAL_MS) + return; + + fps->last_timestamp = now; + fps->last_frame_counter = fps->curr_frame_counter; + fpks = (num_frames * 1000000) / ms_since_last; + snprintf(plane->fps_info.fps_str, FPS_LENGTH, "%-6s @ %d.%.3d fps", + sti_plane_to_str(plane), fpks / 1000, fpks % 1000); + + if (fps->curr_field_counter) { + /* Compute number of field updates */ + num_fields = fps->curr_field_counter - fps->last_field_counter; + fps->last_field_counter = fps->curr_field_counter; + fipks = (num_fields * 1000000) / ms_since_last; + snprintf(plane->fps_info.fips_str, + FPS_LENGTH, " - %d.%.3d field/sec", + fipks / 1000, fipks % 1000); + } else { + plane->fps_info.fips_str[0] = '\0'; + } + + if (fps->output) + DRM_INFO("%s%s\n", + plane->fps_info.fps_str, + plane->fps_info.fips_str); +} + static void sti_plane_destroy(struct drm_plane *drm_plane) { DRM_DEBUG_DRIVER("\n"); diff --git a/drivers/gpu/drm/sti/sti_plane.h b/drivers/gpu/drm/sti/sti_plane.h index 86f1e6f..c50a3b9 100644 --- a/drivers/gpu/drm/sti/sti_plane.h +++ b/drivers/gpu/drm/sti/sti_plane.h @@ -50,6 +50,18 @@ enum sti_plane_status { STI_PLANE_DISABLED, };
+#define FPS_LENGTH 64 +struct sti_fps_info { + bool output; + unsigned int curr_frame_counter; + unsigned int last_frame_counter; + unsigned int curr_field_counter; + unsigned int last_field_counter; + struct timespec last_timestamp; + char fps_str[FPS_LENGTH]; + char fips_str[FPS_LENGTH]; +}; + /** * STI plane structure * @@ -57,15 +69,20 @@ enum sti_plane_status { * @desc: plane type & id * @status: to know the status of the plane * @zorder: plane z-order + * @fps_info: frame per second info */ struct sti_plane { struct drm_plane drm_plane; enum sti_plane_desc desc; enum sti_plane_status status; int zorder; + struct sti_fps_info fps_info; };
const char *sti_plane_to_str(struct sti_plane *plane); +void sti_plane_update_fps(struct sti_plane *plane, + bool new_frame, + bool new_field); void sti_plane_init_property(struct sti_plane *plane, enum drm_plane_type type); #endif
On Fri, Feb 12, 2016 at 10:13:59AM +0100, Vincent Abriou wrote:
Those patches introduce debugfs for connector, encoder, crtc and planes. It adds the following entries:
planes: gdpx / gdpx_node hqvdp cursor vid fps_get / fps_show
crtc: mixer_aux / mixer_main
encoder: tvout
connectors: hda hdmi dvo
Just noticed that all your debugfs files lock dev->struct_mutex. That's pure cargo-cult garbage. Please fix asap and replace the useless locking you have with the right ones where needed (e.g. modeset structures where never protected by dev->struct_mutex). Did someone bother to review the locking in these patches?
Thanks, Daniel
Vincent Abriou (10): drm/sti: add debugfs entries for HDMI connector drm/sti: add debugfs entries for DVO connector drm/sti: add debugfs entries for HDA connector drm/sti: add debugfs entries for CURSOR plane drm/sti: add debugfs entries for GDP planes drm/sti: add debugfs entries for HQVDP plane drm/sti: add debugfs entries for VID plane drm/sti: add debugfs entries for MIXER crtc drm/sti: add debugfs entries for TVOUT encoders drm/sti: add debugfs fps_show/fps_get mechanism for planes
drivers/gpu/drm/sti/sti_compositor.c | 4 +- drivers/gpu/drm/sti/sti_cursor.c | 81 +++++++++++ drivers/gpu/drm/sti/sti_drv.c | 128 ++++++++++++++++++ drivers/gpu/drm/sti/sti_dvo.c | 70 ++++++++++ drivers/gpu/drm/sti/sti_gdp.c | 238 ++++++++++++++++++++++++++++++++ drivers/gpu/drm/sti/sti_hda.c | 105 ++++++++++++++- drivers/gpu/drm/sti/sti_hdmi.c | 175 +++++++++++++++++++++++- drivers/gpu/drm/sti/sti_hdmi.h | 4 +- drivers/gpu/drm/sti/sti_hqvdp.c | 254 ++++++++++++++++++++++++++++++++++- drivers/gpu/drm/sti/sti_mixer.c | 146 +++++++++++++++++++- drivers/gpu/drm/sti/sti_mixer.h | 4 +- drivers/gpu/drm/sti/sti_plane.c | 63 +++++++++ drivers/gpu/drm/sti/sti_plane.h | 17 +++ drivers/gpu/drm/sti/sti_tvout.c | 157 ++++++++++++++++++++++ drivers/gpu/drm/sti/sti_vid.c | 94 ++++++++++++- drivers/gpu/drm/sti/sti_vid.h | 4 +- 16 files changed, 1524 insertions(+), 20 deletions(-)
-- 1.9.1
dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
dri-devel@lists.freedesktop.org