msm: mdss: add debugfs support for LCM debug
Register debugfs nodes to read from and write to the LCM registers. Give following command in adb shell to read panel register: echo address feedback_count > /d/mdp/panel_off cat /d/mdp/panel_reg To write panel register: echo address value > /d/mdp/panel_reg Change-Id: I9ef9fb57dc1b7dea42c7e701c60018f7946ee75b Signed-off-by: Ray Zhang <rayz@codeaurora.org>
This commit is contained in:
parent
a506802723
commit
7e0c6813e2
5 changed files with 291 additions and 1 deletions
|
@ -25,12 +25,290 @@
|
|||
#include "mdss_mdp.h"
|
||||
#include "mdss_mdp_hwio.h"
|
||||
#include "mdss_debug.h"
|
||||
#include "mdss_dsi.h"
|
||||
|
||||
#define DEFAULT_BASE_REG_CNT 0x100
|
||||
#define GROUP_BYTES 4
|
||||
#define ROW_BYTES 16
|
||||
#define MAX_VSYNC_COUNT 0xFFFFFFF
|
||||
|
||||
#define DEFAULT_READ_PANEL_POWER_MODE_REG 0x0A
|
||||
#define PANEL_RX_MAX_BUF 128
|
||||
#define PANEL_TX_MAX_BUF 64
|
||||
#define PANEL_CMD_MIN_TX_COUNT 2
|
||||
#define PANEL_DATA_NODE_LEN 80
|
||||
|
||||
static char panel_reg[2] = {DEFAULT_READ_PANEL_POWER_MODE_REG, 0x00};
|
||||
|
||||
static int panel_debug_base_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
/* non-seekable */
|
||||
file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE);
|
||||
file->private_data = inode->i_private;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int panel_debug_base_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct mdss_debug_base *dbg = file->private_data;
|
||||
if (dbg && dbg->buf) {
|
||||
kfree(dbg->buf);
|
||||
dbg->buf_len = 0;
|
||||
dbg->buf = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t panel_debug_base_offset_write(struct file *file,
|
||||
const char __user *user_buf, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct mdss_debug_base *dbg = file->private_data;
|
||||
u32 off = 0;
|
||||
u32 cnt = DEFAULT_BASE_REG_CNT;
|
||||
char buf[PANEL_RX_MAX_BUF] = {0x0};
|
||||
|
||||
if (!dbg)
|
||||
return -ENODEV;
|
||||
|
||||
if (count >= sizeof(buf))
|
||||
return -EFAULT;
|
||||
|
||||
if (copy_from_user(buf, user_buf, count))
|
||||
return -EFAULT;
|
||||
|
||||
buf[count] = 0; /* end of string */
|
||||
|
||||
if (sscanf(buf, "%x %x", &off, &cnt) != 2)
|
||||
return -EFAULT;
|
||||
|
||||
if (off > dbg->max_offset)
|
||||
return -EINVAL;
|
||||
|
||||
if (cnt > (dbg->max_offset - off))
|
||||
cnt = dbg->max_offset - off;
|
||||
|
||||
dbg->off = off;
|
||||
dbg->cnt = cnt;
|
||||
|
||||
pr_debug("offset=%x cnt=%x\n", off, cnt);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t panel_debug_base_offset_read(struct file *file,
|
||||
char __user *buff, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct mdss_debug_base *dbg = file->private_data;
|
||||
int len = 0;
|
||||
char buf[PANEL_RX_MAX_BUF] = {0x0};
|
||||
|
||||
if (!dbg)
|
||||
return -ENODEV;
|
||||
|
||||
if (*ppos)
|
||||
return 0; /* the end */
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "0x%02zx %zx\n", dbg->off, dbg->cnt);
|
||||
if (len < 0)
|
||||
return 0;
|
||||
|
||||
if (copy_to_user(buff, buf, len))
|
||||
return -EFAULT;
|
||||
|
||||
*ppos += len; /* increase offset */
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t panel_debug_base_reg_write(struct file *file,
|
||||
const char __user *user_buf, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct mdss_debug_base *dbg = file->private_data;
|
||||
|
||||
u32 cnt, tmp, i;
|
||||
u32 len = 0;
|
||||
char buf[PANEL_TX_MAX_BUF] = {0x0};
|
||||
char *p = NULL;
|
||||
char reg[PANEL_TX_MAX_BUF] = {0x0};
|
||||
|
||||
struct mdss_data_type *mdata = mdss_res;
|
||||
struct mdss_mdp_ctl *ctl = mdata->ctl_off + 0;
|
||||
struct mdss_panel_data *panel_data = ctl->panel_data;
|
||||
struct mdss_dsi_ctrl_pdata *ctrl_pdata = container_of(panel_data,
|
||||
struct mdss_dsi_ctrl_pdata, panel_data);
|
||||
|
||||
struct dsi_cmd_desc dsi_write_cmd = {
|
||||
{DTYPE_GEN_LWRITE, 1, 0, 0, 0, 0/*len*/}, reg};
|
||||
struct dcs_cmd_req cmdreq;
|
||||
|
||||
cmdreq.cmds = &dsi_write_cmd;
|
||||
cmdreq.cmds_cnt = 1;
|
||||
cmdreq.flags = CMD_REQ_COMMIT;
|
||||
cmdreq.rlen = 0;
|
||||
cmdreq.cb = NULL;
|
||||
|
||||
if (!dbg || !mdata)
|
||||
return -ENODEV;
|
||||
|
||||
if (count >= sizeof(buf))
|
||||
return -EFAULT;
|
||||
|
||||
if (copy_from_user(buf, user_buf, count))
|
||||
return -EFAULT;
|
||||
|
||||
buf[count] = 0; /* end of string */
|
||||
|
||||
len = count / 3;
|
||||
|
||||
if (len < PANEL_CMD_MIN_TX_COUNT) {
|
||||
pr_err("wrong input reg len\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
p = buf + i * 3;
|
||||
p[2] = 0;
|
||||
pr_debug("p[%d] = %p:%s\n", i, p, p);
|
||||
cnt = sscanf(p, "%x", &tmp);
|
||||
reg[i] = tmp;
|
||||
pr_debug("reg[%d] = %x\n", i, (int)reg[i]);
|
||||
}
|
||||
|
||||
if (mdata->debug_inf.debug_enable_clock)
|
||||
mdata->debug_inf.debug_enable_clock(1);
|
||||
|
||||
dsi_write_cmd.dchdr.dlen = len;
|
||||
mdss_dsi_cmdlist_put(ctrl_pdata, &cmdreq);
|
||||
|
||||
if (mdata->debug_inf.debug_enable_clock)
|
||||
mdata->debug_inf.debug_enable_clock(0);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t panel_debug_base_reg_read(struct file *file,
|
||||
char __user *user_buf, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct mdss_debug_base *dbg = file->private_data;
|
||||
int len = 0;
|
||||
int rx_len = 0;
|
||||
int i, lx = 0;
|
||||
char to_user_buf[PANEL_RX_MAX_BUF] = {0x0};
|
||||
char panel_reg_buf[PANEL_RX_MAX_BUF] = {0x0};
|
||||
char rx_buf[PANEL_RX_MAX_BUF] = {0x0};
|
||||
struct mdss_data_type *mdata = mdss_res;
|
||||
struct mdss_mdp_ctl *ctl = mdata->ctl_off + 0;
|
||||
struct mdss_panel_data *panel_data = ctl->panel_data;
|
||||
struct mdss_dsi_ctrl_pdata *ctrl_pdata = container_of(panel_data,
|
||||
struct mdss_dsi_ctrl_pdata, panel_data);
|
||||
|
||||
if (!dbg)
|
||||
return -ENODEV;
|
||||
|
||||
if (*ppos)
|
||||
return 0; /* the end */
|
||||
|
||||
if (mdata->debug_inf.debug_enable_clock)
|
||||
mdata->debug_inf.debug_enable_clock(1);
|
||||
|
||||
panel_reg[0] = dbg->off;
|
||||
mdss_dsi_panel_cmd_read(ctrl_pdata, panel_reg[0],
|
||||
panel_reg[1], NULL, rx_buf, dbg->cnt);
|
||||
|
||||
rx_len = ctrl_pdata->rx_len;
|
||||
|
||||
for (i = 0; i < rx_len; i++) {
|
||||
lx += snprintf(panel_reg_buf + lx, sizeof(panel_reg_buf),
|
||||
"%s%02x", " 0x", rx_buf[i]);
|
||||
}
|
||||
|
||||
pr_debug("%s:lx =%d,panel_reg_buf= %s,data[%d]=%x\n",
|
||||
__func__, lx, panel_reg_buf, i, rx_buf[i]);
|
||||
|
||||
len = snprintf(to_user_buf, sizeof(to_user_buf), "0x%02zx:%s\n",
|
||||
dbg->off, panel_reg_buf);
|
||||
|
||||
if (mdata->debug_inf.debug_enable_clock)
|
||||
mdata->debug_inf.debug_enable_clock(0);
|
||||
|
||||
if (len < 0)
|
||||
return 0;
|
||||
|
||||
if (copy_to_user(user_buf, to_user_buf, len))
|
||||
return -EFAULT;
|
||||
|
||||
*ppos += len; /* increase offset */
|
||||
return len;
|
||||
}
|
||||
|
||||
static const struct file_operations panel_off_fops = {
|
||||
.open = panel_debug_base_open,
|
||||
.release = panel_debug_base_release,
|
||||
.read = panel_debug_base_offset_read,
|
||||
.write = panel_debug_base_offset_write,
|
||||
};
|
||||
|
||||
static const struct file_operations panel_reg_fops = {
|
||||
.open = panel_debug_base_open,
|
||||
.release = panel_debug_base_release,
|
||||
.read = panel_debug_base_reg_read,
|
||||
.write = panel_debug_base_reg_write,
|
||||
};
|
||||
|
||||
int panel_debug_register_base(const char *name, void __iomem *base,
|
||||
size_t max_offset)
|
||||
{
|
||||
struct mdss_data_type *mdata = mdss_res;
|
||||
struct mdss_debug_data *mdd;
|
||||
struct mdss_debug_base *dbg;
|
||||
struct dentry *ent_off, *ent_reg;
|
||||
char dn[PANEL_DATA_NODE_LEN] = "";
|
||||
int prefix_len = 0;
|
||||
|
||||
if (!mdata || !mdata->debug_inf.debug_data)
|
||||
return -ENODEV;
|
||||
|
||||
mdd = mdata->debug_inf.debug_data;
|
||||
|
||||
dbg = kzalloc(sizeof(*dbg), GFP_KERNEL);
|
||||
if (!dbg)
|
||||
return -ENOMEM;
|
||||
|
||||
dbg->base = base;
|
||||
dbg->max_offset = max_offset;
|
||||
dbg->off = 0x0a;
|
||||
dbg->cnt = 0x01;
|
||||
|
||||
if (name)
|
||||
prefix_len = snprintf(dn, sizeof(dn), "%s_", name);
|
||||
|
||||
strlcpy(dn + prefix_len, "off", sizeof(dn) - prefix_len);
|
||||
ent_off = debugfs_create_file(dn, 0644, mdd->root,
|
||||
dbg, &panel_off_fops);
|
||||
|
||||
if (IS_ERR_OR_NULL(ent_off)) {
|
||||
pr_err("debugfs_create_file: offset fail\n");
|
||||
goto off_fail;
|
||||
}
|
||||
|
||||
strlcpy(dn + prefix_len, "reg", sizeof(dn) - prefix_len);
|
||||
ent_reg = debugfs_create_file(dn, 0644, mdd->root,
|
||||
dbg, &panel_reg_fops);
|
||||
if (IS_ERR_OR_NULL(ent_reg)) {
|
||||
pr_err("debugfs_create_file: reg fail\n");
|
||||
goto reg_fail;
|
||||
}
|
||||
|
||||
list_add(&dbg->head, &mdd->base_list);
|
||||
|
||||
return 0;
|
||||
reg_fail:
|
||||
debugfs_remove(ent_off);
|
||||
off_fail:
|
||||
kfree(dbg);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static int mdss_debug_base_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
/* non-seekable */
|
||||
|
|
|
@ -126,6 +126,8 @@ int mdss_debug_register_base(const char *name, void __iomem *base,
|
|||
void mdss_debug_register_dump_range(struct platform_device *pdev,
|
||||
struct mdss_debug_base *blk_base, const char *ranges_prop,
|
||||
const char *name_prop);
|
||||
int panel_debug_register_base(const char *name, void __iomem *base,
|
||||
size_t max_offset);
|
||||
int mdss_misr_set(struct mdss_data_type *mdata, struct mdp_misr *req,
|
||||
struct mdss_mdp_ctl *ctl);
|
||||
int mdss_misr_get(struct mdss_data_type *mdata, struct mdp_misr *resp,
|
||||
|
@ -146,6 +148,10 @@ static inline int mdss_debug_register_base(const char *name, void __iomem *base,
|
|||
static inline void mdss_debug_register_dump_range(struct platform_device *pdev,
|
||||
struct mdss_debug_base *blk_base, const char *ranges_prop,
|
||||
const char *name_prop) { return 0; }
|
||||
static inline int panel_debug_register_base(const char *name,
|
||||
void __iomem *base,
|
||||
size_t max_offset)
|
||||
{ return 0; }
|
||||
static inline int mdss_misr_set(struct mdss_data_type *mdata,
|
||||
struct mdp_misr *req,
|
||||
struct mdss_mdp_ctl *ctl)
|
||||
|
|
|
@ -2079,6 +2079,9 @@ int dsi_panel_device_register(struct device_node *pan_node,
|
|||
ctrl_pdata->ndx = 1;
|
||||
}
|
||||
|
||||
panel_debug_register_base("panel",
|
||||
ctrl_pdata->ctrl_base, ctrl_pdata->reg_size);
|
||||
|
||||
pr_debug("%s: Panel data initialized\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -394,6 +394,7 @@ struct mdss_dsi_ctrl_pdata {
|
|||
struct dsi_buf rx_buf;
|
||||
struct dsi_buf status_buf;
|
||||
int status_mode;
|
||||
int rx_len;
|
||||
|
||||
struct dsi_pinctrl_res pin_res;
|
||||
|
||||
|
@ -477,7 +478,8 @@ void mdss_dsi_ctrl_setup(struct mdss_dsi_ctrl_pdata *ctrl);
|
|||
void mdss_dsi_dln0_phy_err(struct mdss_dsi_ctrl_pdata *ctrl);
|
||||
void mdss_dsi_lp_cd_rx(struct mdss_dsi_ctrl_pdata *ctrl);
|
||||
void mdss_dsi_get_hw_revision(struct mdss_dsi_ctrl_pdata *ctrl);
|
||||
|
||||
u32 mdss_dsi_panel_cmd_read(struct mdss_dsi_ctrl_pdata *ctrl, char cmd0,
|
||||
char cmd1, void (*fxn)(int), char *rbuf, int len);
|
||||
int mdss_dsi_panel_init(struct device_node *node,
|
||||
struct mdss_dsi_ctrl_pdata *ctrl_pdata,
|
||||
bool cmd_cfg_cont_splash);
|
||||
|
|
|
@ -1944,6 +1944,7 @@ int mdss_dsi_cmdlist_rx(struct mdss_dsi_ctrl_pdata *ctrl,
|
|||
rp = &ctrl->rx_buf;
|
||||
len = mdss_dsi_cmds_rx(ctrl, req->cmds, req->rlen);
|
||||
memcpy(req->rbuf, rp->data, rp->len);
|
||||
ctrl->rx_len = len;
|
||||
} else {
|
||||
pr_err("%s: No rx buffer provided\n", __func__);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue