From: Thierry Reding <treding@xxxxxxxxxx> Currently the mipi_dsi_dcs_write() function requires the DCS command byte to be embedded within the write buffer whereas mipi_dsi_dcs_read() has a separate parameter. Make them more symmetrical by adding an extra command parameter to mipi_dsi_dcs_write(). The S6E8AA0 driver relies on the old asymmetric API and there's concern that moving to the new API may be less efficient. Provide a new function with the old semantics for those cases and make the S6E8AA0 driver use it instead. Signed-off-by: Thierry Reding <treding@xxxxxxxxxx> --- Changes in v2: - provide mipi_dsi_dcs_write_buffer() for backwards compatibility drivers/gpu/drm/drm_mipi_dsi.c | 127 +++++++++++++++++++++++++++++----- drivers/gpu/drm/panel/panel-s6e8aa0.c | 2 +- include/drm/drm_mipi_dsi.h | 6 +- 3 files changed, 114 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index eb6dfe52cab2..1702ffd07986 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -199,33 +199,120 @@ int mipi_dsi_detach(struct mipi_dsi_device *dsi) EXPORT_SYMBOL(mipi_dsi_detach); /** - * mipi_dsi_dcs_write - send DCS write command - * @dsi: DSI device - * @data: pointer to the command followed by parameters - * @len: length of @data + * mipi_dsi_dcs_write_buffer() - transmit a DCS command with payload + * @dsi: DSI peripheral device + * @data: buffer containing data to be transmitted + * @len: size of transmission buffer + * + * This function will automatically choose the right data type depending on + * the command payload length. + * + * Return: The number of bytes successfully transmitted or a negative error + * code on failure. */ -ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, const void *data, - size_t len) +ssize_t mipi_dsi_dcs_write_buffer(struct mipi_dsi_device *dsi, + const void *data, size_t len) { - const struct mipi_dsi_host_ops *ops = dsi->host->ops; struct mipi_dsi_msg msg = { .channel = dsi->channel, .tx_buf = data, .tx_len = len }; - if (!ops || !ops->transfer) + if (!dsi->host->ops || !dsi->host->ops->transfer) return -ENOSYS; switch (len) { case 0: return -EINVAL; + case 1: msg.type = MIPI_DSI_DCS_SHORT_WRITE; break; + case 2: msg.type = MIPI_DSI_DCS_SHORT_WRITE_PARAM; break; + + default: + msg.type = MIPI_DSI_DCS_LONG_WRITE; + break; + } + + return dsi->host->ops->transfer(dsi->host, &msg); +} +EXPORT_SYMBOL(mipi_dsi_dcs_write_buffer); + +/** + * mipi_dsi_dcs_write() - send DCS write command + * @dsi: DSI peripheral device + * @cmd: DCS command + * @data: buffer containing the command payload + * @len: command payload length + * + * This function will automatically choose the right data type depending on + * the command payload length. + * + * Return: The number of bytes successfully transmitted or a negative error + * code on failure. + */ +ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, u8 cmd, + const void *data, size_t len) +{ + struct mipi_dsi_msg msg; + ssize_t err; + size_t size; + u8 *tx; + + if (!dsi->host->ops || !dsi->host->ops->transfer) + return -ENOSYS; + + if (len > 0) { + unsigned int offset = 0; + + /* + * DCS long write packets contain the word count in the header + * bytes 1 and 2 and have a payload containing the DCS command + * byte folowed by word count minus one bytes. + * + * DCS short write packets encode the DCS command and up to + * one parameter in header bytes 1 and 2. + */ + if (len > 1) + size = 3 + len; + else + size = 1 + len; + + tx = kmalloc(size, GFP_KERNEL); + if (!tx) + return -ENOMEM; + + /* write word count to header for DCS long write packets */ + if (len > 1) { + tx[offset++] = ((1 + len) >> 0) & 0xff; + tx[offset++] = ((1 + len) >> 8) & 0xff; + } + + /* write the DCS command byte followed by the payload */ + tx[offset++] = cmd; + memcpy(tx + offset, data, len); + } else { + tx = &cmd; + size = 1; + } + + memset(&msg, 0, sizeof(msg)); + msg.channel = dsi->channel; + msg.tx_len = size; + msg.tx_buf = tx; + + switch (len) { + case 0: + msg.type = MIPI_DSI_DCS_SHORT_WRITE; + break; + case 1: + msg.type = MIPI_DSI_DCS_SHORT_WRITE_PARAM; + break; default: msg.type = MIPI_DSI_DCS_LONG_WRITE; break; @@ -234,23 +321,27 @@ ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, const void *data, if (dsi->mode_flags & MIPI_DSI_MODE_LPM) msg.flags = MIPI_DSI_MSG_USE_LPM; - return ops->transfer(dsi->host, &msg); + err = dsi->host->ops->transfer(dsi->host, &msg); + + if (len > 0) + kfree(tx); + + return err; } EXPORT_SYMBOL(mipi_dsi_dcs_write); /** - * mipi_dsi_dcs_read - send DCS read request command - * @dsi: DSI device - * @cmd: DCS read command - * @data: pointer to read buffer - * @len: length of @data + * mipi_dsi_dcs_read() - send DCS read request command + * @dsi: DSI peripheral device + * @cmd: DCS command + * @data: buffer in which to receive data + * @len: size of receive buffer * - * Function returns number of read bytes or error code. + * Return: The number of bytes read or a negative error code on failure. */ ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, u8 cmd, void *data, size_t len) { - const struct mipi_dsi_host_ops *ops = dsi->host->ops; struct mipi_dsi_msg msg = { .channel = dsi->channel, .type = MIPI_DSI_DCS_READ, @@ -260,13 +351,13 @@ ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, u8 cmd, void *data, .rx_len = len }; - if (!ops || !ops->transfer) + if (!dsi->host->ops || !dsi->host->ops->transfer) return -ENOSYS; if (dsi->mode_flags & MIPI_DSI_MODE_LPM) msg.flags = MIPI_DSI_MSG_USE_LPM; - return ops->transfer(dsi->host, &msg); + return dsi->host->ops->transfer(dsi->host, &msg); } EXPORT_SYMBOL(mipi_dsi_dcs_read); diff --git a/drivers/gpu/drm/panel/panel-s6e8aa0.c b/drivers/gpu/drm/panel/panel-s6e8aa0.c index b5217fe37f02..0f85a7c37687 100644 --- a/drivers/gpu/drm/panel/panel-s6e8aa0.c +++ b/drivers/gpu/drm/panel/panel-s6e8aa0.c @@ -141,7 +141,7 @@ static void s6e8aa0_dcs_write(struct s6e8aa0 *ctx, const void *data, size_t len) if (ctx->error < 0) return; - ret = mipi_dsi_dcs_write(dsi, data, len); + ret = mipi_dsi_dcs_write_buffer(dsi, data, len); if (ret < 0) { dev_err(ctx->dev, "error %zd writing dcs seq: %*ph\n", ret, len, data); diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index 8569dc5a1026..ccc3869e137b 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -132,8 +132,10 @@ static inline struct mipi_dsi_device *to_mipi_dsi_device(struct device *dev) int mipi_dsi_attach(struct mipi_dsi_device *dsi); int mipi_dsi_detach(struct mipi_dsi_device *dsi); -ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, const void *data, - size_t len); +ssize_t mipi_dsi_dcs_write_buffer(struct mipi_dsi_device *dsi, + const void *data, size_t len); +ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, u8 cmd, + const void *data, size_t len); ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, u8 cmd, void *data, size_t len); -- 2.1.2 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel