disp: msm: debugfs interface for sde connector to do DSI read

This change implements a new feature to read the cmds response
of the panel from sde connector interface. Sde connector opens
debugfs interface for all the connectors those have support for
cmd receive operation.

Sde connector init module creates rx_cmd debugfs file at
/<debugfs-root>/dri/0/DSI-1/ for DSI-1 connector.
Format for DSI command transfer:
echo "command bytes" > /<debugfs-root/dri/0/DSI-1/rx_cmd
byte-0: the length of received buffer
byte-1: data-type
byte-2: last command. always 0x01
byte-3: channel number
byte-4: flags. MIPI_DSI_MSG_*, must be set to 0xa
byte-5: 0x00
byte-6 and byte-7: command payload length
byte-8 to byte-[8+payload length]: command payload
Example:
echo "0x01 0x06 0x01 0x00 0x0a 0x00 0x00 0x01 0x0a" > rx_cmd
The command receive operations are allowed only if controller
(ex. DSI controller) is in active state.
Read the value of panel response:
cat /<debugfs-root>/dri/0/DSI-1/rx_cmd
returns the value of this command.
nothing - failure, xx xx - success.

Change-Id: I912b65d606e248c7a886d219f4363bf7766ee7b6
Signed-off-by: Yuan Zhao <yzhao@codeaurora.org>
这个提交包含在:
Yuan Zhao
2020-05-12 14:44:03 +08:00
提交者 Gerrit - the friendly Code Review server
父节点 4fbdcba865
当前提交 5bba78331d
修改 5 个文件,包含 327 行新增18 行删除

查看文件

@@ -1774,8 +1774,8 @@ static ssize_t _sde_debugfs_conn_cmd_tx_sts_read(struct file *file,
char __user *buf, size_t count, loff_t *ppos)
{
struct drm_connector *connector = file->private_data;
struct sde_connector *c_conn;
char buffer[MAX_CMD_PAYLOAD_SIZE];
struct sde_connector *c_conn = NULL;
char buffer[MAX_CMD_PAYLOAD_SIZE] = {0};
int blen = 0;
if (*ppos)
@@ -1783,7 +1783,7 @@ static ssize_t _sde_debugfs_conn_cmd_tx_sts_read(struct file *file,
if (!connector) {
SDE_ERROR("invalid argument, conn is NULL\n");
return 0;
return -EINVAL;
}
c_conn = to_sde_connector(connector);
@@ -1797,7 +1797,7 @@ static ssize_t _sde_debugfs_conn_cmd_tx_sts_read(struct file *file,
SDE_DEBUG("output: %s\n", buffer);
if (blen <= 0) {
SDE_ERROR("snprintf failed, blen %d\n", blen);
return 0;
return -EINVAL;
}
if (blen > count)
@@ -1817,16 +1817,16 @@ static ssize_t _sde_debugfs_conn_cmd_tx_write(struct file *file,
const char __user *p, size_t count, loff_t *ppos)
{
struct drm_connector *connector = file->private_data;
struct sde_connector *c_conn;
struct sde_connector *c_conn = NULL;
char *input, *token, *input_copy, *input_dup = NULL;
const char *delim = " ";
char buffer[MAX_CMD_PAYLOAD_SIZE] = {0};
int rc = 0, strtoint = 0;
u32 buf_size = 0;
char buffer[MAX_CMD_PAYLOAD_SIZE];
int rc = 0, strtoint;
if (*ppos || !connector) {
SDE_ERROR("invalid argument(s), conn %d\n", connector != NULL);
return 0;
return -EINVAL;
}
c_conn = to_sde_connector(connector);
@@ -1834,10 +1834,10 @@ static ssize_t _sde_debugfs_conn_cmd_tx_write(struct file *file,
if (!c_conn->ops.cmd_transfer) {
SDE_ERROR("no cmd transfer support for connector name %s\n",
c_conn->name);
return 0;
return -EINVAL;
}
input = kmalloc(count + 1, GFP_KERNEL);
input = kzalloc(count + 1, GFP_KERNEL);
if (!input)
return -ENOMEM;
@@ -1848,7 +1848,7 @@ static ssize_t _sde_debugfs_conn_cmd_tx_write(struct file *file,
}
input[count] = '\0';
SDE_INFO("Command requested for trasnfer to panel: %s\n", input);
SDE_INFO("Command requested for transfer to panel: %s\n", input);
input_copy = kstrdup(input, GFP_KERNEL);
if (!input_copy) {
@@ -1862,20 +1862,23 @@ static ssize_t _sde_debugfs_conn_cmd_tx_write(struct file *file,
rc = kstrtoint(token, 0, &strtoint);
if (rc) {
SDE_ERROR("input buffer conversion failed\n");
goto end;
goto end1;
}
buffer[buf_size++] = (strtoint & 0xff);
if (buf_size >= MAX_CMD_PAYLOAD_SIZE) {
SDE_ERROR("buffer size exceeding the limit %d\n",
MAX_CMD_PAYLOAD_SIZE);
goto end;
rc = -EFAULT;
goto end1;
}
buffer[buf_size++] = (strtoint & 0xff);
token = strsep(&input_copy, delim);
}
SDE_DEBUG("command packet size in bytes: %u\n", buf_size);
if (!buf_size)
goto end;
if (!buf_size) {
rc = -EFAULT;
goto end1;
}
mutex_lock(&c_conn->lock);
rc = c_conn->ops.cmd_transfer(&c_conn->base, c_conn->display, buffer,
@@ -1884,8 +1887,9 @@ static ssize_t _sde_debugfs_conn_cmd_tx_write(struct file *file,
mutex_unlock(&c_conn->lock);
rc = count;
end:
end1:
kfree(input_dup);
end:
kfree(input);
return rc;
}
@@ -1896,6 +1900,177 @@ static const struct file_operations conn_cmd_tx_fops = {
.write = _sde_debugfs_conn_cmd_tx_write,
};
static int _sde_debugfs_conn_cmd_rx_open(struct inode *inode, struct file *file)
{
/* non-seekable */
file->private_data = inode->i_private;
return nonseekable_open(inode, file);
}
static ssize_t _sde_debugfs_conn_cmd_rx_read(struct file *file,
char __user *buf, size_t count, loff_t *ppos)
{
struct drm_connector *connector = file->private_data;
struct sde_connector *c_conn = NULL;
char *strs = NULL;
char *strs_temp = NULL;
int blen = 0, i = 0, n = 0, left_size = 0;
if (*ppos)
return 0;
if (!connector) {
SDE_ERROR("invalid argument, conn is NULL\n");
return -EINVAL;
}
c_conn = to_sde_connector(connector);
if (c_conn->rx_len <= 0 || c_conn->rx_len > MAX_CMD_RECEIVE_SIZE) {
SDE_ERROR("no valid data from panel\n");
return -EINVAL;
}
/*
* Rx data was stored as HEX value in rx buffer,
* convert 1 HEX value to strings for display, need 5 bytes.
* for example: HEX value 0xFF, converted to strings, should be '0',
* 'x','F','F' and 1 space.
*/
left_size = c_conn->rx_len * 5 + 1;
strs = kzalloc(left_size, GFP_KERNEL);
if (!strs)
return -ENOMEM;
strs_temp = strs;
mutex_lock(&c_conn->lock);
for (i = 0; i < c_conn->rx_len; i++) {
n = scnprintf(strs_temp, left_size, "0x%.2x ",
c_conn->cmd_rx_buf[i]);
strs_temp += n;
left_size -= n;
}
mutex_unlock(&c_conn->lock);
blen = strlen(strs);
if (blen <= 0) {
SDE_ERROR("snprintf failed, blen %d\n", blen);
blen = -EFAULT;
goto err;
}
if (copy_to_user(buf, strs, blen)) {
SDE_ERROR("copy to user buffer failed\n");
blen = -EFAULT;
goto err;
}
*ppos += blen;
err:
kfree(strs);
return blen;
}
static ssize_t _sde_debugfs_conn_cmd_rx_write(struct file *file,
const char __user *p, size_t count, loff_t *ppos)
{
struct drm_connector *connector = file->private_data;
struct sde_connector *c_conn = NULL;
char *input, *token, *input_copy, *input_dup = NULL;
const char *delim = " ";
unsigned char buffer[MAX_CMD_PAYLOAD_SIZE] = {0};
int rc = 0, strtoint = 0;
u32 buf_size = 0;
if (*ppos || !connector) {
SDE_ERROR("invalid argument(s), conn %d\n", connector != NULL);
return -EINVAL;
}
c_conn = to_sde_connector(connector);
if (!c_conn->ops.cmd_receive) {
SDE_ERROR("no cmd receive support for connector name %s\n",
c_conn->name);
return -EINVAL;
}
memset(c_conn->cmd_rx_buf, 0x0, MAX_CMD_RECEIVE_SIZE);
c_conn->rx_len = 0;
input = kzalloc(count + 1, GFP_KERNEL);
if (!input)
return -ENOMEM;
if (copy_from_user(input, p, count)) {
SDE_ERROR("copy from user failed\n");
rc = -EFAULT;
goto end;
}
input[count] = '\0';
SDE_INFO("Command requested for rx from panel: %s\n", input);
input_copy = kstrdup(input, GFP_KERNEL);
if (!input_copy) {
rc = -ENOMEM;
goto end;
}
input_dup = input_copy;
token = strsep(&input_copy, delim);
while (token) {
rc = kstrtoint(token, 0, &strtoint);
if (rc) {
SDE_ERROR("input buffer conversion failed\n");
goto end1;
}
buffer[buf_size++] = (strtoint & 0xff);
if (buf_size >= MAX_CMD_PAYLOAD_SIZE) {
SDE_ERROR("buffer size = %d exceeding the limit %d\n",
buf_size, MAX_CMD_PAYLOAD_SIZE);
rc = -EFAULT;
goto end1;
}
token = strsep(&input_copy, delim);
}
if (!buffer[0] || buffer[0] > MAX_CMD_RECEIVE_SIZE) {
SDE_ERROR("invalid rx length\n");
rc = -EFAULT;
goto end1;
}
SDE_DEBUG("command packet size in bytes: %u, rx len: %u\n",
buf_size, buffer[0]);
if (!buf_size) {
rc = -EFAULT;
goto end1;
}
mutex_lock(&c_conn->lock);
c_conn->rx_len = c_conn->ops.cmd_receive(c_conn->display, buffer + 1,
buf_size - 1, c_conn->cmd_rx_buf, buffer[0]);
mutex_unlock(&c_conn->lock);
if (c_conn->rx_len <= 0)
rc = -EINVAL;
else
rc = count;
end1:
kfree(input_dup);
end:
kfree(input);
return rc;
}
static const struct file_operations conn_cmd_rx_fops = {
.open = _sde_debugfs_conn_cmd_rx_open,
.read = _sde_debugfs_conn_cmd_rx_read,
.write = _sde_debugfs_conn_cmd_rx_write,
};
#ifdef CONFIG_DEBUG_FS
/**
* sde_connector_init_debugfs - initialize connector debugfs
@@ -1936,6 +2111,15 @@ static int sde_connector_init_debugfs(struct drm_connector *connector)
}
}
if (sde_connector->ops.cmd_receive) {
if (!debugfs_create_file("rx_cmd", 0600,
connector->debugfs_entry,
connector, &conn_cmd_rx_fops)) {
SDE_ERROR("failed to create connector cmd_rx\n");
return -ENOMEM;
}
}
return 0;
}
#else