Merge "disp: msm: debugfs interface for sde connector to do DSI read"
This commit is contained in:

committed by
Gerrit - the friendly Code Review server

commit
5c92c5ac78
@@ -918,6 +918,58 @@ static int dsi_display_ctrl_get_host_init_state(struct dsi_display *dsi_display,
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int dsi_display_cmd_rx(struct dsi_display *display,
|
||||
struct dsi_cmd_desc *cmd)
|
||||
{
|
||||
struct dsi_display_ctrl *m_ctrl = NULL;
|
||||
u32 mask = 0, flags = 0;
|
||||
int rc = 0;
|
||||
|
||||
if (!display || !display->panel)
|
||||
return -EINVAL;
|
||||
|
||||
m_ctrl = &display->ctrl[display->cmd_master_idx];
|
||||
if (!m_ctrl || !m_ctrl->ctrl)
|
||||
return -EINVAL;
|
||||
|
||||
/* acquire panel_lock to make sure no commands are in progress */
|
||||
dsi_panel_acquire_panel_lock(display->panel);
|
||||
if (!display->panel->panel_initialized) {
|
||||
DSI_DEBUG("panel not initialized\n");
|
||||
goto release_panel_lock;
|
||||
}
|
||||
|
||||
rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
|
||||
DSI_ALL_CLKS, DSI_CLK_ON);
|
||||
if (rc)
|
||||
goto release_panel_lock;
|
||||
|
||||
mask = BIT(DSI_FIFO_OVERFLOW) | BIT(DSI_FIFO_UNDERFLOW);
|
||||
dsi_display_mask_ctrl_error_interrupts(display, mask, true);
|
||||
rc = dsi_display_cmd_engine_enable(display);
|
||||
if (rc) {
|
||||
DSI_ERR("cmd engine enable failed rc = %d\n", rc);
|
||||
goto error;
|
||||
}
|
||||
|
||||
flags |= (DSI_CTRL_CMD_FETCH_MEMORY | DSI_CTRL_CMD_READ |
|
||||
DSI_CTRL_CMD_CUSTOM_DMA_SCHED);
|
||||
rc = dsi_ctrl_cmd_transfer(m_ctrl->ctrl, &cmd->msg, &flags);
|
||||
if (rc <= 0)
|
||||
DSI_ERR("rx cmd transfer failed rc = %d\n", rc);
|
||||
|
||||
dsi_display_cmd_engine_disable(display);
|
||||
|
||||
error:
|
||||
dsi_display_mask_ctrl_error_interrupts(display, mask, false);
|
||||
dsi_display_clk_ctrl(display->dsi_clk_handle,
|
||||
DSI_ALL_CLKS, DSI_CLK_OFF);
|
||||
release_panel_lock:
|
||||
dsi_panel_release_panel_lock(display->panel);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int dsi_display_cmd_transfer(struct drm_connector *connector,
|
||||
void *display, const char *cmd_buf,
|
||||
u32 cmd_buf_len)
|
||||
@@ -984,6 +1036,48 @@ static void _dsi_display_continuous_clk_ctrl(struct dsi_display *display,
|
||||
}
|
||||
}
|
||||
|
||||
int dsi_display_cmd_receive(void *display, const char *cmd_buf,
|
||||
u32 cmd_buf_len, u8 *recv_buf, u32 recv_buf_len)
|
||||
{
|
||||
struct dsi_display *dsi_display = display;
|
||||
struct dsi_cmd_desc cmd = {};
|
||||
u8 cmd_payload[MAX_CMD_PAYLOAD_SIZE] = {0};
|
||||
bool state = false;
|
||||
int rc = -1;
|
||||
|
||||
if (!dsi_display || !cmd_buf || !recv_buf) {
|
||||
DSI_ERR("[DSI] invalid params\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = dsi_display_cmd_prepare(cmd_buf, cmd_buf_len,
|
||||
&cmd, cmd_payload, MAX_CMD_PAYLOAD_SIZE);
|
||||
if (rc) {
|
||||
DSI_ERR("[DSI] command prepare failed, rc = %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
cmd.msg.rx_buf = recv_buf;
|
||||
cmd.msg.rx_len = recv_buf_len;
|
||||
|
||||
mutex_lock(&dsi_display->display_lock);
|
||||
rc = dsi_display_ctrl_get_host_init_state(dsi_display, &state);
|
||||
if (rc || !state) {
|
||||
DSI_ERR("[DSI] Invalid host state = %d rc = %d\n",
|
||||
state, rc);
|
||||
rc = -EPERM;
|
||||
goto end;
|
||||
}
|
||||
|
||||
rc = dsi_display_cmd_rx(dsi_display, &cmd);
|
||||
if (rc <= 0)
|
||||
DSI_ERR("[DSI] Display command receive failed, rc=%d\n", rc);
|
||||
|
||||
end:
|
||||
mutex_unlock(&dsi_display->display_lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int dsi_display_soft_reset(void *display)
|
||||
{
|
||||
struct dsi_display *dsi_display;
|
||||
|
@@ -653,6 +653,17 @@ int dsi_display_cmd_transfer(struct drm_connector *connector,
|
||||
void *display, const char *cmd_buffer,
|
||||
u32 cmd_buf_len);
|
||||
|
||||
/**
|
||||
* dsi_display_cmd_receive() - receive response from the panel
|
||||
* @display: Handle to display.
|
||||
* @cmd_buf: Command buffer
|
||||
* @cmd_buf_len: Command buffer length in bytes
|
||||
* @recv_buf: Receive buffer
|
||||
* @recv_buf_len: Receive buffer length in bytes
|
||||
*/
|
||||
int dsi_display_cmd_receive(void *display, const char *cmd_buf,
|
||||
u32 cmd_buf_len, u8 *recv_buf, u32 recv_buf_len);
|
||||
|
||||
/**
|
||||
* dsi_display_soft_reset() - perform a soft reset on DSI controller
|
||||
* @display: Handle to display
|
||||
|
@@ -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
|
||||
|
@@ -18,6 +18,7 @@
|
||||
|
||||
#define SDE_CONNECTOR_NAME_SIZE 16
|
||||
#define SDE_CONNECTOR_DHDR_MEMPOOL_MAX_SIZE SZ_32
|
||||
#define MAX_CMD_RECEIVE_SIZE 256
|
||||
|
||||
struct sde_connector;
|
||||
struct sde_connector_state;
|
||||
@@ -263,6 +264,18 @@ struct sde_connector_ops {
|
||||
int (*cmd_transfer)(struct drm_connector *connector,
|
||||
void *display, const char *cmd_buf,
|
||||
u32 cmd_buf_len);
|
||||
/**
|
||||
* cmd_receive - Receive the response from the connected display panel
|
||||
* @display: Pointer to private display handle
|
||||
* @cmd_buf: Command buffer
|
||||
* @cmd_buf_len: Command buffer length in bytes
|
||||
* @recv_buf: rx buffer
|
||||
* @recv_buf_len: rx buffer length
|
||||
* Returns: number of bytes read, if successful, negative for failure
|
||||
*/
|
||||
|
||||
int (*cmd_receive)(void *display, const char *cmd_buf,
|
||||
u32 cmd_buf_len, u8 *recv_buf, u32 recv_buf_len);
|
||||
|
||||
/**
|
||||
* config_hdr - configure HDR
|
||||
@@ -433,7 +446,8 @@ struct sde_connector_dyn_hdr_metadata {
|
||||
* @colorspace_updated: Colorspace property was updated
|
||||
* @last_cmd_tx_sts: status of the last command transfer
|
||||
* @hdr_capable: external hdr support present
|
||||
* @core_clk_rate: MDP core clk rate used for dynamic HDR packet calculation
|
||||
* @cmd_rx_buf: the return buffer of response of command transfer
|
||||
* @rx_len: the length of dcs command received buffer
|
||||
*/
|
||||
struct sde_connector {
|
||||
struct drm_connector base;
|
||||
@@ -498,6 +512,9 @@ struct sde_connector {
|
||||
|
||||
bool last_cmd_tx_sts;
|
||||
bool hdr_capable;
|
||||
|
||||
u8 cmd_rx_buf[MAX_CMD_RECEIVE_SIZE];
|
||||
int rx_len;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@@ -1322,6 +1322,7 @@ static int _sde_kms_setup_displays(struct drm_device *dev,
|
||||
.cont_splash_config = dsi_display_cont_splash_config,
|
||||
.get_panel_vfp = dsi_display_get_panel_vfp,
|
||||
.get_default_lms = dsi_display_get_default_lms,
|
||||
.cmd_receive = dsi_display_cmd_receive,
|
||||
};
|
||||
static const struct sde_connector_ops wb_ops = {
|
||||
.post_init = sde_wb_connector_post_init,
|
||||
@@ -1337,6 +1338,7 @@ static int _sde_kms_setup_displays(struct drm_device *dev,
|
||||
.cmd_transfer = NULL,
|
||||
.cont_splash_config = NULL,
|
||||
.get_panel_vfp = NULL,
|
||||
.cmd_receive = NULL,
|
||||
};
|
||||
static const struct sde_connector_ops dp_ops = {
|
||||
.post_init = dp_connector_post_init,
|
||||
@@ -1354,6 +1356,7 @@ static int _sde_kms_setup_displays(struct drm_device *dev,
|
||||
.cont_splash_config = NULL,
|
||||
.get_panel_vfp = NULL,
|
||||
.update_pps = dp_connector_update_pps,
|
||||
.cmd_receive = NULL,
|
||||
};
|
||||
struct msm_display_info info;
|
||||
struct drm_encoder *encoder;
|
||||
|
Reference in New Issue
Block a user