Loading drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c +21 −0 Original line number Diff line number Diff line Loading @@ -2830,6 +2830,27 @@ static void _dsi_ctrl_cache_misr(struct dsi_ctrl *dsi_ctrl) dsi_ctrl->misr_cache); } /** * dsi_ctrl_get_host_engine_init_state() - Return host init state * @dsi_ctrl: DSI controller handle. * @state: Controller initialization state * * Return: error code. */ int dsi_ctrl_get_host_engine_init_state(struct dsi_ctrl *dsi_ctrl, bool *state) { if (!dsi_ctrl || !state) { pr_err("Invalid Params\n"); return -EINVAL; } mutex_lock(&dsi_ctrl->ctrl_lock); *state = dsi_ctrl->current_state.host_initialized; mutex_unlock(&dsi_ctrl->ctrl_lock); return 0; } /** * dsi_ctrl_update_host_engine_state_for_cont_splash() - Loading drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h +7 −0 Original line number Diff line number Diff line Loading @@ -717,4 +717,11 @@ void dsi_ctrl_isr_configure(struct dsi_ctrl *dsi_ctrl, bool enable); * @enable: variable to control enable/disable irq line */ void dsi_ctrl_irq_update(struct dsi_ctrl *dsi_ctrl, bool enable); /** * dsi_ctrl_get_host_engine_init_state() - Return host init state */ int dsi_ctrl_get_host_engine_init_state(struct dsi_ctrl *dsi_ctrl, bool *state); #endif /* _DSI_CTRL_H_ */ drivers/gpu/drm/msm/dsi-staging/dsi_display.c +81 −0 Original line number Diff line number Diff line Loading @@ -564,6 +564,87 @@ int dsi_display_check_status(void *display) return rc; } static int dsi_display_cmd_prepare(const char *cmd_buf, u32 cmd_buf_len, struct dsi_cmd_desc *cmd, u8 *payload, u32 payload_len) { int i; memset(cmd, 0x00, sizeof(*cmd)); cmd->msg.type = cmd_buf[0]; cmd->last_command = (cmd_buf[1] == 1 ? true : false); cmd->msg.channel = cmd_buf[2]; cmd->msg.flags = cmd_buf[3]; cmd->msg.ctrl = 0; cmd->post_wait_ms = cmd_buf[4]; cmd->msg.tx_len = ((cmd_buf[5] << 8) | (cmd_buf[6])); if (cmd->msg.tx_len > payload_len) { pr_err("Incorrect payload length tx_len %ld, payload_len %d\n", cmd->msg.tx_len, payload_len); return -EINVAL; } for (i = 0; i < cmd->msg.tx_len; i++) payload[i] = cmd_buf[7 + i]; cmd->msg.tx_buf = payload; return 0; } static int dsi_display_ctrl_get_host_init_state(struct dsi_display *dsi_display, bool *state) { struct dsi_display_ctrl *ctrl; int i, rc = -EINVAL; for (i = 0 ; i < dsi_display->ctrl_count; i++) { ctrl = &dsi_display->ctrl[i]; rc = dsi_ctrl_get_host_engine_init_state(ctrl->ctrl, state); if (rc) break; } return rc; } int dsi_display_cmd_transfer(void *display, const char *cmd_buf, u32 cmd_buf_len) { struct dsi_display *dsi_display = display; struct dsi_cmd_desc cmd; u8 cmd_payload[MAX_CMD_PAYLOAD_SIZE]; int rc = 0; bool state = false; if (!dsi_display || !cmd_buf) { pr_err("[DSI] invalid params\n"); return -EINVAL; } pr_debug("[DSI] Display command transfer\n"); rc = dsi_display_cmd_prepare(cmd_buf, cmd_buf_len, &cmd, cmd_payload, MAX_CMD_PAYLOAD_SIZE); if (rc) { pr_err("[DSI] command prepare failed. rc %d\n", rc); return rc; } mutex_lock(&dsi_display->display_lock); rc = dsi_display_ctrl_get_host_init_state(dsi_display, &state); if (rc || !state) { pr_err("[DSI] Invalid host state %d rc %d\n", state, rc); rc = -EPERM; goto end; } rc = dsi_display->host.ops->transfer(&dsi_display->host, &cmd.msg); end: mutex_unlock(&dsi_display->display_lock); return rc; } int dsi_display_soft_reset(void *display) { struct dsi_display *dsi_display; Loading drivers/gpu/drm/msm/dsi-staging/dsi_display.h +10 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ #define MAX_DSI_CTRLS_PER_DISPLAY 2 #define DSI_CLIENT_NAME_SIZE 20 #define MAX_CMDLINE_PARAM_LEN 512 #define MAX_CMD_PAYLOAD_SIZE 256 /* * DSI Validate Mode modifiers * @DSI_VALIDATE_FLAG_ALLOW_ADJUST: Allow mode validation to also do fixup Loading Loading @@ -535,6 +536,15 @@ int dsi_display_set_backlight(void *display, u32 bl_lvl); */ int dsi_display_check_status(void *display); /** * dsi_display_cmd_transfer() - transfer command to the panel * @display: Handle to display. * @cmd_buf: Command buffer * @cmd_buf_len: Command buffer length in bytes */ int dsi_display_cmd_transfer(void *display, const char *cmd_buffer, u32 cmd_buf_len); /** * dsi_display_soft_reset() - perform a soft reset on DSI controller * @display: Handle to display Loading drivers/gpu/drm/msm/sde/sde_connector.c +139 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #include "sde_connector.h" #include "sde_encoder.h" #include <linux/backlight.h> #include <linux/string.h> #include "dsi_drm.h" #include "dsi_display.h" #include "sde_crtc.h" Loading Loading @@ -1357,6 +1358,135 @@ int sde_connector_helper_reset_custom_properties( return 0; } static int _sde_debugfs_conn_cmd_tx_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_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]; int blen = 0; if (*ppos) return 0; if (!connector) { SDE_ERROR("invalid argument, conn is NULL\n"); return 0; } c_conn = to_sde_connector(connector); mutex_lock(&c_conn->lock); blen = snprintf(buffer, MAX_CMD_PAYLOAD_SIZE, "last_cmd_tx_sts:0x%x", c_conn->last_cmd_tx_sts); mutex_unlock(&c_conn->lock); SDE_DEBUG("output: %s\n", buffer); if (blen <= 0) { SDE_ERROR("snprintf failed, blen %d\n", blen); return 0; } if (copy_to_user(buf, buffer, blen)) { SDE_ERROR("copy to user buffer failed\n"); return -EFAULT; } *ppos += blen; return blen; } 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; char *input, *token, *input_copy, *input_dup = NULL; const char *delim = " "; 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; } c_conn = to_sde_connector(connector); if (!c_conn->ops.cmd_transfer) { SDE_ERROR("no cmd transfer support for connector name %s\n", c_conn->name); return 0; } input = kmalloc(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_DEBUG("input: %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 end; } if (buf_size >= MAX_CMD_PAYLOAD_SIZE) { SDE_ERROR("buffer size exceeding the limit %d\n", MAX_CMD_PAYLOAD_SIZE); goto end; } 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; mutex_lock(&c_conn->lock); rc = c_conn->ops.cmd_transfer(c_conn->display, buffer, buf_size); c_conn->last_cmd_tx_sts = !rc ? true : false; mutex_unlock(&c_conn->lock); rc = count; end: kfree(input_dup); kfree(input); return rc; } static const struct file_operations conn_cmd_tx_fops = { .open = _sde_debugfs_conn_cmd_tx_open, .read = _sde_debugfs_conn_cmd_tx_sts_read, .write = _sde_debugfs_conn_cmd_tx_write, }; #ifdef CONFIG_DEBUG_FS /** * sde_connector_init_debugfs - initialize connector debugfs Loading Loading @@ -1387,6 +1517,15 @@ static int sde_connector_init_debugfs(struct drm_connector *connector) return -ENOMEM; } if (sde_connector->ops.cmd_transfer) { if (!debugfs_create_file("tx_cmd", 0600, connector->debugfs_entry, connector, &conn_cmd_tx_fops)) { SDE_ERROR("failed to create connector cmd_tx\n"); return -ENOMEM; } } return 0; } #else Loading Loading
drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c +21 −0 Original line number Diff line number Diff line Loading @@ -2830,6 +2830,27 @@ static void _dsi_ctrl_cache_misr(struct dsi_ctrl *dsi_ctrl) dsi_ctrl->misr_cache); } /** * dsi_ctrl_get_host_engine_init_state() - Return host init state * @dsi_ctrl: DSI controller handle. * @state: Controller initialization state * * Return: error code. */ int dsi_ctrl_get_host_engine_init_state(struct dsi_ctrl *dsi_ctrl, bool *state) { if (!dsi_ctrl || !state) { pr_err("Invalid Params\n"); return -EINVAL; } mutex_lock(&dsi_ctrl->ctrl_lock); *state = dsi_ctrl->current_state.host_initialized; mutex_unlock(&dsi_ctrl->ctrl_lock); return 0; } /** * dsi_ctrl_update_host_engine_state_for_cont_splash() - Loading
drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h +7 −0 Original line number Diff line number Diff line Loading @@ -717,4 +717,11 @@ void dsi_ctrl_isr_configure(struct dsi_ctrl *dsi_ctrl, bool enable); * @enable: variable to control enable/disable irq line */ void dsi_ctrl_irq_update(struct dsi_ctrl *dsi_ctrl, bool enable); /** * dsi_ctrl_get_host_engine_init_state() - Return host init state */ int dsi_ctrl_get_host_engine_init_state(struct dsi_ctrl *dsi_ctrl, bool *state); #endif /* _DSI_CTRL_H_ */
drivers/gpu/drm/msm/dsi-staging/dsi_display.c +81 −0 Original line number Diff line number Diff line Loading @@ -564,6 +564,87 @@ int dsi_display_check_status(void *display) return rc; } static int dsi_display_cmd_prepare(const char *cmd_buf, u32 cmd_buf_len, struct dsi_cmd_desc *cmd, u8 *payload, u32 payload_len) { int i; memset(cmd, 0x00, sizeof(*cmd)); cmd->msg.type = cmd_buf[0]; cmd->last_command = (cmd_buf[1] == 1 ? true : false); cmd->msg.channel = cmd_buf[2]; cmd->msg.flags = cmd_buf[3]; cmd->msg.ctrl = 0; cmd->post_wait_ms = cmd_buf[4]; cmd->msg.tx_len = ((cmd_buf[5] << 8) | (cmd_buf[6])); if (cmd->msg.tx_len > payload_len) { pr_err("Incorrect payload length tx_len %ld, payload_len %d\n", cmd->msg.tx_len, payload_len); return -EINVAL; } for (i = 0; i < cmd->msg.tx_len; i++) payload[i] = cmd_buf[7 + i]; cmd->msg.tx_buf = payload; return 0; } static int dsi_display_ctrl_get_host_init_state(struct dsi_display *dsi_display, bool *state) { struct dsi_display_ctrl *ctrl; int i, rc = -EINVAL; for (i = 0 ; i < dsi_display->ctrl_count; i++) { ctrl = &dsi_display->ctrl[i]; rc = dsi_ctrl_get_host_engine_init_state(ctrl->ctrl, state); if (rc) break; } return rc; } int dsi_display_cmd_transfer(void *display, const char *cmd_buf, u32 cmd_buf_len) { struct dsi_display *dsi_display = display; struct dsi_cmd_desc cmd; u8 cmd_payload[MAX_CMD_PAYLOAD_SIZE]; int rc = 0; bool state = false; if (!dsi_display || !cmd_buf) { pr_err("[DSI] invalid params\n"); return -EINVAL; } pr_debug("[DSI] Display command transfer\n"); rc = dsi_display_cmd_prepare(cmd_buf, cmd_buf_len, &cmd, cmd_payload, MAX_CMD_PAYLOAD_SIZE); if (rc) { pr_err("[DSI] command prepare failed. rc %d\n", rc); return rc; } mutex_lock(&dsi_display->display_lock); rc = dsi_display_ctrl_get_host_init_state(dsi_display, &state); if (rc || !state) { pr_err("[DSI] Invalid host state %d rc %d\n", state, rc); rc = -EPERM; goto end; } rc = dsi_display->host.ops->transfer(&dsi_display->host, &cmd.msg); end: mutex_unlock(&dsi_display->display_lock); return rc; } int dsi_display_soft_reset(void *display) { struct dsi_display *dsi_display; Loading
drivers/gpu/drm/msm/dsi-staging/dsi_display.h +10 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ #define MAX_DSI_CTRLS_PER_DISPLAY 2 #define DSI_CLIENT_NAME_SIZE 20 #define MAX_CMDLINE_PARAM_LEN 512 #define MAX_CMD_PAYLOAD_SIZE 256 /* * DSI Validate Mode modifiers * @DSI_VALIDATE_FLAG_ALLOW_ADJUST: Allow mode validation to also do fixup Loading Loading @@ -535,6 +536,15 @@ int dsi_display_set_backlight(void *display, u32 bl_lvl); */ int dsi_display_check_status(void *display); /** * dsi_display_cmd_transfer() - transfer command to the panel * @display: Handle to display. * @cmd_buf: Command buffer * @cmd_buf_len: Command buffer length in bytes */ int dsi_display_cmd_transfer(void *display, const char *cmd_buffer, u32 cmd_buf_len); /** * dsi_display_soft_reset() - perform a soft reset on DSI controller * @display: Handle to display Loading
drivers/gpu/drm/msm/sde/sde_connector.c +139 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #include "sde_connector.h" #include "sde_encoder.h" #include <linux/backlight.h> #include <linux/string.h> #include "dsi_drm.h" #include "dsi_display.h" #include "sde_crtc.h" Loading Loading @@ -1357,6 +1358,135 @@ int sde_connector_helper_reset_custom_properties( return 0; } static int _sde_debugfs_conn_cmd_tx_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_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]; int blen = 0; if (*ppos) return 0; if (!connector) { SDE_ERROR("invalid argument, conn is NULL\n"); return 0; } c_conn = to_sde_connector(connector); mutex_lock(&c_conn->lock); blen = snprintf(buffer, MAX_CMD_PAYLOAD_SIZE, "last_cmd_tx_sts:0x%x", c_conn->last_cmd_tx_sts); mutex_unlock(&c_conn->lock); SDE_DEBUG("output: %s\n", buffer); if (blen <= 0) { SDE_ERROR("snprintf failed, blen %d\n", blen); return 0; } if (copy_to_user(buf, buffer, blen)) { SDE_ERROR("copy to user buffer failed\n"); return -EFAULT; } *ppos += blen; return blen; } 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; char *input, *token, *input_copy, *input_dup = NULL; const char *delim = " "; 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; } c_conn = to_sde_connector(connector); if (!c_conn->ops.cmd_transfer) { SDE_ERROR("no cmd transfer support for connector name %s\n", c_conn->name); return 0; } input = kmalloc(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_DEBUG("input: %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 end; } if (buf_size >= MAX_CMD_PAYLOAD_SIZE) { SDE_ERROR("buffer size exceeding the limit %d\n", MAX_CMD_PAYLOAD_SIZE); goto end; } 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; mutex_lock(&c_conn->lock); rc = c_conn->ops.cmd_transfer(c_conn->display, buffer, buf_size); c_conn->last_cmd_tx_sts = !rc ? true : false; mutex_unlock(&c_conn->lock); rc = count; end: kfree(input_dup); kfree(input); return rc; } static const struct file_operations conn_cmd_tx_fops = { .open = _sde_debugfs_conn_cmd_tx_open, .read = _sde_debugfs_conn_cmd_tx_sts_read, .write = _sde_debugfs_conn_cmd_tx_write, }; #ifdef CONFIG_DEBUG_FS /** * sde_connector_init_debugfs - initialize connector debugfs Loading Loading @@ -1387,6 +1517,15 @@ static int sde_connector_init_debugfs(struct drm_connector *connector) return -ENOMEM; } if (sde_connector->ops.cmd_transfer) { if (!debugfs_create_file("tx_cmd", 0600, connector->debugfs_entry, connector, &conn_cmd_tx_fops)) { SDE_ERROR("failed to create connector cmd_tx\n"); return -ENOMEM; } } return 0; } #else Loading