drm/komeda: Add debugfs node "register" for register dump
authorjames qian wang (Arm Technology China) <james.qian.wang@arm.com>
Tue, 22 Jan 2019 09:24:34 +0000 (09:24 +0000)
committerLiviu Dudau <Liviu.Dudau@arm.com>
Mon, 1 Apr 2019 17:09:18 +0000 (18:09 +0100)
Add a debugfs node "register" and entry function dump_register to
dev/pipeline/component to register dump, then user can read
"/sys/kernel/debug/komeda/register" to get the register values via these
chip function.

Signed-off-by: James Qian Wang (Arm Technology China) <james.qian.wang@arm.com>
[Added the d71_layer_dump() function that was in a previous commit]
Signed-off-by: Liviu Dudau <liviu.dudau@arm.com>
drivers/gpu/drm/arm/display/komeda/d71/d71_component.c
drivers/gpu/drm/arm/display/komeda/komeda_dev.c
drivers/gpu/drm/arm/display/komeda/komeda_dev.h
drivers/gpu/drm/arm/display/komeda/komeda_pipeline.c
drivers/gpu/drm/arm/display/komeda/komeda_pipeline.h

index 006fe8fb4153850d762debda59ab314f78f7d0df..c56cfc2de14746188d73fa48de740257a8867bd6 100644 (file)
@@ -71,6 +71,42 @@ static u32 get_valid_inputs(struct block_header *blk)
        return valid_inputs;
 }
 
+static void get_values_from_reg(void __iomem *reg, u32 offset,
+                               u32 count, u32 *val)
+{
+       u32 i, addr;
+
+       for (i = 0; i < count; i++) {
+               addr = offset + (i << 2);
+               /* 0xA4 is WO register */
+               if (addr != 0xA4)
+                       val[i] = malidp_read32(reg, addr);
+               else
+                       val[i] = 0xDEADDEAD;
+       }
+}
+
+static void dump_block_header(struct seq_file *sf, void __iomem *reg)
+{
+       struct block_header hdr;
+       u32 i, n_input, n_output;
+
+       d71_read_block_header(reg, &hdr);
+       seq_printf(sf, "BLOCK_INFO:\t\t0x%X\n", hdr.block_info);
+       seq_printf(sf, "PIPELINE_INFO:\t\t0x%X\n", hdr.pipeline_info);
+
+       n_output = PIPELINE_INFO_N_OUTPUTS(hdr.pipeline_info);
+       n_input  = PIPELINE_INFO_N_VALID_INPUTS(hdr.pipeline_info);
+
+       for (i = 0; i < n_input; i++)
+               seq_printf(sf, "VALID_INPUT_ID%u:\t0x%X\n",
+                          i, hdr.input_ids[i]);
+
+       for (i = 0; i < n_output; i++)
+               seq_printf(sf, "OUTPUT_ID%u:\t\t0x%X\n",
+                          i, hdr.output_ids[i]);
+}
+
 static u32 to_rot_ctrl(u32 rot)
 {
        u32 lr_ctrl = 0;
@@ -143,9 +179,76 @@ static void d71_layer_update(struct komeda_component *c,
        malidp_write32_mask(reg, BLK_CONTROL, ctrl_mask, ctrl);
 }
 
+static void d71_layer_dump(struct komeda_component *c, struct seq_file *sf)
+{
+       u32 v[15], i;
+       bool rich, rgb2rgb;
+       char *prefix;
+
+       get_values_from_reg(c->reg, LAYER_INFO, 1, &v[14]);
+       if (v[14] & 0x1) {
+               rich = true;
+               prefix = "LR_";
+       } else {
+               rich = false;
+               prefix = "LS_";
+       }
+
+       rgb2rgb = !!(v[14] & L_INFO_CM);
+
+       dump_block_header(sf, c->reg);
+
+       seq_printf(sf, "%sLAYER_INFO:\t\t0x%X\n", prefix, v[14]);
+
+       get_values_from_reg(c->reg, 0xD0, 1, v);
+       seq_printf(sf, "%sCONTROL:\t\t0x%X\n", prefix, v[0]);
+       if (rich) {
+               get_values_from_reg(c->reg, 0xD4, 1, v);
+               seq_printf(sf, "LR_RICH_CONTROL:\t0x%X\n", v[0]);
+       }
+       get_values_from_reg(c->reg, 0xD8, 4, v);
+       seq_printf(sf, "%sFORMAT:\t\t0x%X\n", prefix, v[0]);
+       seq_printf(sf, "%sIT_COEFFTAB:\t\t0x%X\n", prefix, v[1]);
+       seq_printf(sf, "%sIN_SIZE:\t\t0x%X\n", prefix, v[2]);
+       seq_printf(sf, "%sPALPHA:\t\t0x%X\n", prefix, v[3]);
+
+       get_values_from_reg(c->reg, 0x100, 3, v);
+       seq_printf(sf, "%sP0_PTR_LOW:\t\t0x%X\n", prefix, v[0]);
+       seq_printf(sf, "%sP0_PTR_HIGH:\t\t0x%X\n", prefix, v[1]);
+       seq_printf(sf, "%sP0_STRIDE:\t\t0x%X\n", prefix, v[2]);
+
+       get_values_from_reg(c->reg, 0x110, 2, v);
+       seq_printf(sf, "%sP1_PTR_LOW:\t\t0x%X\n", prefix, v[0]);
+       seq_printf(sf, "%sP1_PTR_HIGH:\t\t0x%X\n", prefix, v[1]);
+       if (rich) {
+               get_values_from_reg(c->reg, 0x118, 1, v);
+               seq_printf(sf, "LR_P1_STRIDE:\t\t0x%X\n", v[0]);
+
+               get_values_from_reg(c->reg, 0x120, 2, v);
+               seq_printf(sf, "LR_P2_PTR_LOW:\t\t0x%X\n", v[0]);
+               seq_printf(sf, "LR_P2_PTR_HIGH:\t\t0x%X\n", v[1]);
+
+               get_values_from_reg(c->reg, 0x130, 12, v);
+               for (i = 0; i < 12; i++)
+                       seq_printf(sf, "LR_YUV_RGB_COEFF%u:\t0x%X\n", i, v[i]);
+       }
+
+       if (rgb2rgb) {
+               get_values_from_reg(c->reg, LAYER_RGB_RGB_COEFF0, 12, v);
+               for (i = 0; i < 12; i++)
+                       seq_printf(sf, "LS_RGB_RGB_COEFF%u:\t0x%X\n", i, v[i]);
+       }
+
+       get_values_from_reg(c->reg, 0x160, 3, v);
+       seq_printf(sf, "%sAD_CONTROL:\t\t0x%X\n", prefix, v[0]);
+       seq_printf(sf, "%sAD_H_CROP:\t\t0x%X\n", prefix, v[1]);
+       seq_printf(sf, "%sAD_V_CROP:\t\t0x%X\n", prefix, v[2]);
+}
+
 static struct komeda_component_funcs d71_layer_funcs = {
        .update         = d71_layer_update,
        .disable        = d71_layer_disable,
+       .dump_register  = d71_layer_dump,
 };
 
 static int d71_layer_init(struct d71_dev *d71,
@@ -252,9 +355,46 @@ static void d71_compiz_update(struct komeda_component *c,
        malidp_write32(reg, BLK_SIZE, HV_SIZE(st->hsize, st->vsize));
 }
 
+static void d71_compiz_dump(struct komeda_component *c, struct seq_file *sf)
+{
+       u32 v[8], i;
+
+       dump_block_header(sf, c->reg);
+
+       get_values_from_reg(c->reg, 0x80, 5, v);
+       for (i = 0; i < 5; i++)
+               seq_printf(sf, "CU_INPUT_ID%u:\t\t0x%X\n", i, v[i]);
+
+       get_values_from_reg(c->reg, 0xA0, 5, v);
+       seq_printf(sf, "CU_IRQ_RAW_STATUS:\t0x%X\n", v[0]);
+       seq_printf(sf, "CU_IRQ_CLEAR:\t\t0x%X\n", v[1]);
+       seq_printf(sf, "CU_IRQ_MASK:\t\t0x%X\n", v[2]);
+       seq_printf(sf, "CU_IRQ_STATUS:\t\t0x%X\n", v[3]);
+       seq_printf(sf, "CU_STATUS:\t\t0x%X\n", v[4]);
+
+       get_values_from_reg(c->reg, 0xD0, 2, v);
+       seq_printf(sf, "CU_CONTROL:\t\t0x%X\n", v[0]);
+       seq_printf(sf, "CU_SIZE:\t\t0x%X\n", v[1]);
+
+       get_values_from_reg(c->reg, 0xDC, 1, v);
+       seq_printf(sf, "CU_BG_COLOR:\t\t0x%X\n", v[0]);
+
+       for (i = 0, v[4] = 0xE0; i < 5; i++, v[4] += 0x10) {
+               get_values_from_reg(c->reg, v[4], 3, v);
+               seq_printf(sf, "CU_INPUT%u_SIZE:\t\t0x%X\n", i, v[0]);
+               seq_printf(sf, "CU_INPUT%u_OFFSET:\t0x%X\n", i, v[1]);
+               seq_printf(sf, "CU_INPUT%u_CONTROL:\t0x%X\n", i, v[2]);
+       }
+
+       get_values_from_reg(c->reg, 0x130, 2, v);
+       seq_printf(sf, "CU_USER_LOW:\t\t0x%X\n", v[0]);
+       seq_printf(sf, "CU_USER_HIGH:\t\t0x%X\n", v[1]);
+}
+
 struct komeda_component_funcs d71_compiz_funcs = {
        .update         = d71_compiz_update,
        .disable        = d71_component_disable,
+       .dump_register  = d71_compiz_dump,
 };
 
 static int d71_compiz_init(struct d71_dev *d71,
@@ -300,9 +440,37 @@ static void d71_improc_update(struct komeda_component *c,
        malidp_write32(reg, BLK_SIZE, HV_SIZE(st->hsize, st->vsize));
 }
 
+static void d71_improc_dump(struct komeda_component *c, struct seq_file *sf)
+{
+       u32 v[12], i;
+
+       dump_block_header(sf, c->reg);
+
+       get_values_from_reg(c->reg, 0x80, 2, v);
+       seq_printf(sf, "IPS_INPUT_ID0:\t\t0x%X\n", v[0]);
+       seq_printf(sf, "IPS_INPUT_ID1:\t\t0x%X\n", v[1]);
+
+       get_values_from_reg(c->reg, 0xC0, 1, v);
+       seq_printf(sf, "IPS_INFO:\t\t0x%X\n", v[0]);
+
+       get_values_from_reg(c->reg, 0xD0, 3, v);
+       seq_printf(sf, "IPS_CONTROL:\t\t0x%X\n", v[0]);
+       seq_printf(sf, "IPS_SIZE:\t\t0x%X\n", v[1]);
+       seq_printf(sf, "IPS_DEPTH:\t\t0x%X\n", v[2]);
+
+       get_values_from_reg(c->reg, 0x130, 12, v);
+       for (i = 0; i < 12; i++)
+               seq_printf(sf, "IPS_RGB_RGB_COEFF%u:\t0x%X\n", i, v[i]);
+
+       get_values_from_reg(c->reg, 0x170, 12, v);
+       for (i = 0; i < 12; i++)
+               seq_printf(sf, "IPS_RGB_YUV_COEFF%u:\t0x%X\n", i, v[i]);
+}
+
 struct komeda_component_funcs d71_improc_funcs = {
        .update         = d71_improc_update,
        .disable        = d71_component_disable,
+       .dump_register  = d71_improc_dump,
 };
 
 static int d71_improc_init(struct d71_dev *d71,
@@ -375,9 +543,46 @@ static void d71_timing_ctrlr_update(struct komeda_component *c,
        malidp_write32(reg, BLK_CONTROL, value);
 }
 
+void d71_timing_ctrlr_dump(struct komeda_component *c, struct seq_file *sf)
+{
+       u32 v[8], i;
+
+       dump_block_header(sf, c->reg);
+
+       get_values_from_reg(c->reg, 0xC0, 1, v);
+       seq_printf(sf, "BS_INFO:\t\t0x%X\n", v[0]);
+
+       get_values_from_reg(c->reg, 0xD0, 8, v);
+       seq_printf(sf, "BS_CONTROL:\t\t0x%X\n", v[0]);
+       seq_printf(sf, "BS_PROG_LINE:\t\t0x%X\n", v[1]);
+       seq_printf(sf, "BS_PREFETCH_LINE:\t0x%X\n", v[2]);
+       seq_printf(sf, "BS_BG_COLOR:\t\t0x%X\n", v[3]);
+       seq_printf(sf, "BS_ACTIVESIZE:\t\t0x%X\n", v[4]);
+       seq_printf(sf, "BS_HINTERVALS:\t\t0x%X\n", v[5]);
+       seq_printf(sf, "BS_VINTERVALS:\t\t0x%X\n", v[6]);
+       seq_printf(sf, "BS_SYNC:\t\t0x%X\n", v[7]);
+
+       get_values_from_reg(c->reg, 0x100, 3, v);
+       seq_printf(sf, "BS_DRIFT_TO:\t\t0x%X\n", v[0]);
+       seq_printf(sf, "BS_FRAME_TO:\t\t0x%X\n", v[1]);
+       seq_printf(sf, "BS_TE_TO:\t\t0x%X\n", v[2]);
+
+       get_values_from_reg(c->reg, 0x110, 3, v);
+       for (i = 0; i < 3; i++)
+               seq_printf(sf, "BS_T%u_INTERVAL:\t\t0x%X\n", i, v[i]);
+
+       get_values_from_reg(c->reg, 0x120, 5, v);
+       for (i = 0; i < 2; i++) {
+               seq_printf(sf, "BS_CRC%u_LOW:\t\t0x%X\n", i, v[i << 1]);
+               seq_printf(sf, "BS_CRC%u_HIGH:\t\t0x%X\n", i, v[(i << 1) + 1]);
+       }
+       seq_printf(sf, "BS_USER:\t\t0x%X\n", v[4]);
+}
+
 struct komeda_component_funcs d71_timing_ctrlr_funcs = {
        .update         = d71_timing_ctrlr_update,
        .disable        = d71_timing_ctrlr_disable,
+       .dump_register  = d71_timing_ctrlr_dump,
 };
 
 static int d71_timing_ctrlr_init(struct d71_dev *d71,
index cf65bf5331d9f8ff4d349def7a092aac52a9f366..b420c6205d6bf136be15da93c97ad624fc141ffd 100644 (file)
@@ -8,11 +8,55 @@
 #include <linux/of_device.h>
 #include <linux/of_graph.h>
 #include <linux/platform_device.h>
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#endif
 
 #include <drm/drm_print.h>
 
 #include "komeda_dev.h"
 
+static int komeda_register_show(struct seq_file *sf, void *x)
+{
+       struct komeda_dev *mdev = sf->private;
+       int i;
+
+       if (mdev->funcs->dump_register)
+               mdev->funcs->dump_register(mdev, sf);
+
+       for (i = 0; i < mdev->n_pipelines; i++)
+               komeda_pipeline_dump_register(mdev->pipelines[i], sf);
+
+       return 0;
+}
+
+static int komeda_register_open(struct inode *inode, struct file *filp)
+{
+       return single_open(filp, komeda_register_show, inode->i_private);
+}
+
+static const struct file_operations komeda_register_fops = {
+       .owner          = THIS_MODULE,
+       .open           = komeda_register_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static void komeda_debugfs_init(struct komeda_dev *mdev)
+{
+       if (!debugfs_initialized())
+               return;
+
+       mdev->debugfs_root = debugfs_create_dir("komeda", NULL);
+       if (IS_ERR_OR_NULL(mdev->debugfs_root))
+               return;
+
+       debugfs_create_file("register", 0444, mdev->debugfs_root,
+                           mdev, &komeda_register_fops);
+}
+
 static int komeda_parse_pipe_dt(struct komeda_dev *mdev, struct device_node *np)
 {
        struct komeda_pipeline *pipe;
@@ -159,6 +203,10 @@ struct komeda_dev *komeda_dev_create(struct device *dev)
                goto err_cleanup;
        }
 
+#ifdef CONFIG_DEBUG_FS
+       komeda_debugfs_init(mdev);
+#endif
+
        return mdev;
 
 err_cleanup:
@@ -172,6 +220,10 @@ void komeda_dev_destroy(struct komeda_dev *mdev)
        struct komeda_dev_funcs *funcs = mdev->funcs;
        int i;
 
+#ifdef CONFIG_DEBUG_FS
+       debugfs_remove_recursive(mdev->debugfs_root);
+#endif
+
        for (i = 0; i < mdev->n_pipelines; i++) {
                komeda_pipeline_destroy(mdev, mdev->pipelines[i]);
                mdev->pipelines[i] = NULL;
index 681fe022bd2209b81db37d708bebf1d895d338fe..8eae2620ce77160095e5da8536fbb154660400d4 100644 (file)
@@ -103,6 +103,9 @@ struct komeda_dev_funcs {
        int (*enable_irq)(struct komeda_dev *mdev);
        /** @disable_irq: disable irq */
        int (*disable_irq)(struct komeda_dev *mdev);
+
+       /** @dump_register: Optional, dump registers to seq_file */
+       void (*dump_register)(struct komeda_dev *mdev, struct seq_file *seq);
 };
 
 /**
@@ -139,6 +142,8 @@ struct komeda_dev {
         * destroyed by &komeda_dev_funcs.cleanup()
         */
        void *chip_data;
+
+       struct dentry *debugfs_root;
 };
 
 static inline bool
index ca85e12312a388c5dd42765cca51ed2d450e4161..07398efc40f57939bb306a37f25cbd45c163dbe4 100644 (file)
@@ -275,3 +275,23 @@ int komeda_assemble_pipelines(struct komeda_dev *mdev)
 
        return 0;
 }
+
+void komeda_pipeline_dump_register(struct komeda_pipeline *pipe,
+                                  struct seq_file *sf)
+{
+       struct komeda_component *c;
+       u32 id;
+
+       seq_printf(sf, "\n======== Pipeline-%d ==========\n", pipe->id);
+
+       if (pipe->funcs && pipe->funcs->dump_register)
+               pipe->funcs->dump_register(pipe, sf);
+
+       dp_for_each_set_bit(id, pipe->avail_comps) {
+               c = komeda_pipeline_get_component(pipe, id);
+
+               seq_printf(sf, "\n------%s------\n", c->name);
+               if (c->funcs->dump_register)
+                       c->funcs->dump_register(c, sf);
+       }
+}
index f9b7f517a48426240adfca58aaf4f9414940b59a..c30a790d0712ec7eb9a0acb80e9304daf10ae4fe 100644 (file)
@@ -367,6 +367,9 @@ int komeda_assemble_pipelines(struct komeda_dev *mdev);
 struct komeda_component *
 komeda_pipeline_get_component(struct komeda_pipeline *pipe, int id);
 
+void komeda_pipeline_dump_register(struct komeda_pipeline *pipe,
+                                  struct seq_file *sf);
+
 /* component APIs */
 struct komeda_component *
 komeda_component_add(struct komeda_pipeline *pipe,