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:
Ray Zhang 2014-12-29 16:45:51 +08:00 committed by David Keitel
parent a506802723
commit 7e0c6813e2
5 changed files with 291 additions and 1 deletions

View file

@ -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 */

View file

@ -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)

View file

@ -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;
}

View file

@ -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);

View file

@ -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__);
}