diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/drm_mipi_dsi.c | 227 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_dsi.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/panel-ld9040.c | 13 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/panel-s6e8aa0.c | 13 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/panel-simple.c | 132 |
5 files changed, 326 insertions, 61 deletions
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index eb6dfe5..388c3ab 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -198,59 +198,238 @@ int mipi_dsi_detach(struct mipi_dsi_device *dsi) } EXPORT_SYMBOL(mipi_dsi_detach); +static ssize_t mipi_dsi_device_transfer(struct mipi_dsi_device *dsi, + struct mipi_dsi_msg *msg) +{ + const struct mipi_dsi_host_ops *ops = dsi->host->ops; + + if (!ops || !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); +} + /** - * 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_packet_format_is_short - check if a packet is of the short format + * @type: MIPI DSI data type of the packet + * + * Return: true if the packet for the given data type is a short packet, false + * otherwise. */ -ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, const void *data, - size_t len) +bool mipi_dsi_packet_format_is_short(u8 type) +{ + switch (type) { + case MIPI_DSI_V_SYNC_START: + case MIPI_DSI_V_SYNC_END: + case MIPI_DSI_H_SYNC_START: + case MIPI_DSI_H_SYNC_END: + case MIPI_DSI_END_OF_TRANSMISSION: + case MIPI_DSI_COLOR_MODE_OFF: + case MIPI_DSI_COLOR_MODE_ON: + case MIPI_DSI_SHUTDOWN_PERIPHERAL: + case MIPI_DSI_TURN_ON_PERIPHERAL: + case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM: + case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM: + case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM: + case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM: + case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM: + case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM: + case MIPI_DSI_DCS_SHORT_WRITE: + case MIPI_DSI_DCS_SHORT_WRITE_PARAM: + case MIPI_DSI_DCS_READ: + case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE: + return true; + } + + return false; +} +EXPORT_SYMBOL(mipi_dsi_packet_format_is_short); + +/** + * mipi_dsi_packet_format_is_long - check if a packet is of the long format + * @type: MIPI DSI data type of the packet + * + * Return: true if the packet for the given data type is a long packet, false + * otherwise. + */ +bool mipi_dsi_packet_format_is_long(u8 type) +{ + switch (type) { + case MIPI_DSI_NULL_PACKET: + case MIPI_DSI_BLANKING_PACKET: + case MIPI_DSI_GENERIC_LONG_WRITE: + case MIPI_DSI_DCS_LONG_WRITE: + case MIPI_DSI_LOOSELY_PACKED_PIXEL_STREAM_YCBCR20: + case MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR24: + case MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16: + case MIPI_DSI_PACKED_PIXEL_STREAM_30: + case MIPI_DSI_PACKED_PIXEL_STREAM_36: + case MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12: + case MIPI_DSI_PACKED_PIXEL_STREAM_16: + case MIPI_DSI_PACKED_PIXEL_STREAM_18: + case MIPI_DSI_PIXEL_STREAM_3BYTE_18: + case MIPI_DSI_PACKED_PIXEL_STREAM_24: + return true; + } + + return false; +} +EXPORT_SYMBOL(mipi_dsi_packet_format_is_long); + +/** + * mipi_dsi_create_packet - create a packet from a message according to the + * DSI protocol + * @packet: pointer to a DSI packet structure + * @msg: message to translate into a packet + * + * Return: 0 on success or a negative error code on failure. + */ +int mipi_dsi_create_packet(struct mipi_dsi_packet *packet, + const struct mipi_dsi_msg *msg) +{ + const u8 *tx = msg->tx_buf; + + if (!packet || !msg) + return -EINVAL; + + /* do some minimum sanity checking */ + if (!mipi_dsi_packet_format_is_short(msg->type) && + !mipi_dsi_packet_format_is_long(msg->type)) + return -EINVAL; + + if (msg->channel > 3) + return -EINVAL; + + memset(packet, 0, sizeof(*packet)); + packet->header[0] = ((msg->channel & 0x3) << 6) | (msg->type & 0x3f); + + /* TODO: compute ECC if hardware support is not available */ + + /* + * Long write packets contain the word count in header bytes 1 and 2. + * The payload follows the header and is word count bytes long. + * + * Short write packets encode up to two parameters in header bytes 1 + * and 2. + */ + if (mipi_dsi_packet_format_is_long(msg->type)) { + packet->header[1] = (msg->tx_len >> 0) & 0xff; + packet->header[2] = (msg->tx_len >> 8) & 0xff; + + packet->payload_length = msg->tx_len; + packet->payload = tx; + } else { + packet->header[1] = (msg->tx_len > 0) ? tx[0] : 0; + packet->header[2] = (msg->tx_len > 1) ? tx[1] : 0; + } + + packet->size = sizeof(packet->header) + packet->payload_length; + + return 0; +} +EXPORT_SYMBOL(mipi_dsi_create_packet); + +/** + * 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_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) - 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; } - if (dsi->mode_flags & MIPI_DSI_MODE_LPM) - msg.flags = MIPI_DSI_MSG_USE_LPM; + return mipi_dsi_device_transfer(dsi, &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) +{ + ssize_t err; + size_t size; + u8 *tx; + + if (len > 0) { + size = 1 + len; + + tx = kmalloc(size, GFP_KERNEL); + if (!tx) + return -ENOMEM; + + /* concatenate the DCS command byte and the payload */ + tx[0] = cmd; + memcpy(&tx[1], data, len); + } else { + tx = &cmd; + size = 1; + } - return ops->transfer(dsi->host, &msg); + err = mipi_dsi_dcs_write_buffer(dsi, tx, size); + + 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 +439,7 @@ ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, u8 cmd, void *data, .rx_len = len }; - if (!ops || !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 mipi_dsi_device_transfer(dsi, &msg); } EXPORT_SYMBOL(mipi_dsi_dcs_read); diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index 24741d8..c5f3c76 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -1236,7 +1236,7 @@ static bool exynos_dsi_is_short_dsi_type(u8 type) } static ssize_t exynos_dsi_host_transfer(struct mipi_dsi_host *host, - struct mipi_dsi_msg *msg) + const struct mipi_dsi_msg *msg) { struct exynos_dsi *dsi = host_to_dsi(host); struct exynos_dsi_transfer xfer; diff --git a/drivers/gpu/drm/panel/panel-ld9040.c b/drivers/gpu/drm/panel/panel-ld9040.c index 42ac67b..08cf2c5 100644 --- a/drivers/gpu/drm/panel/panel-ld9040.c +++ b/drivers/gpu/drm/panel/panel-ld9040.c @@ -145,7 +145,7 @@ static void ld9040_dcs_write(struct ld9040 *ctx, const u8 *data, size_t len) if (ctx->error < 0 || len == 0) return; - dev_dbg(ctx->dev, "writing dcs seq: %*ph\n", len, data); + dev_dbg(ctx->dev, "writing dcs seq: %*ph\n", (int)len, data); ret = ld9040_spi_write_word(ctx, *data); while (!ret && --len) { @@ -154,8 +154,8 @@ static void ld9040_dcs_write(struct ld9040 *ctx, const u8 *data, size_t len) } if (ret) { - dev_err(ctx->dev, "error %d writing dcs seq: %*ph\n", ret, len, - data); + dev_err(ctx->dev, "error %d writing dcs seq: %*ph\n", ret, + (int)len, data); ctx->error = ret; } @@ -336,17 +336,12 @@ static int ld9040_probe(struct spi_device *spi) if (ret < 0) return ret; - ctx->reset_gpio = devm_gpiod_get(dev, "reset"); + ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(ctx->reset_gpio)) { dev_err(dev, "cannot get reset-gpios %ld\n", PTR_ERR(ctx->reset_gpio)); return PTR_ERR(ctx->reset_gpio); } - ret = gpiod_direction_output(ctx->reset_gpio, 1); - if (ret < 0) { - dev_err(dev, "cannot configure reset-gpios %d\n", ret); - return ret; - } spi->bits_per_word = 9; ret = spi_setup(spi); diff --git a/drivers/gpu/drm/panel/panel-s6e8aa0.c b/drivers/gpu/drm/panel/panel-s6e8aa0.c index b5217fe..17bc799 100644 --- a/drivers/gpu/drm/panel/panel-s6e8aa0.c +++ b/drivers/gpu/drm/panel/panel-s6e8aa0.c @@ -141,10 +141,10 @@ 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); + dev_err(ctx->dev, "error %zd writing dcs seq: %*ph\n", ret, + (int)len, data); ctx->error = ret; } } @@ -1019,17 +1019,12 @@ static int s6e8aa0_probe(struct mipi_dsi_device *dsi) return ret; } - ctx->reset_gpio = devm_gpiod_get(dev, "reset"); + ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(ctx->reset_gpio)) { dev_err(dev, "cannot get reset-gpios %ld\n", PTR_ERR(ctx->reset_gpio)); return PTR_ERR(ctx->reset_gpio); } - ret = gpiod_direction_output(ctx->reset_gpio, 1); - if (ret < 0) { - dev_err(dev, "cannot configure reset-gpios %d\n", ret); - return ret; - } ctx->brightness = GAMMA_LEVEL_NUM - 1; diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 23de22f..ce4eb25 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -247,21 +247,14 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc) if (IS_ERR(panel->supply)) return PTR_ERR(panel->supply); - panel->enable_gpio = devm_gpiod_get_optional(dev, "enable"); + panel->enable_gpio = devm_gpiod_get_optional(dev, "enable", + GPIOD_OUT_LOW); if (IS_ERR(panel->enable_gpio)) { err = PTR_ERR(panel->enable_gpio); dev_err(dev, "failed to request GPIO: %d\n", err); return err; } - if (panel->enable_gpio) { - err = gpiod_direction_output(panel->enable_gpio, 0); - if (err < 0) { - dev_err(dev, "failed to setup GPIO: %d\n", err); - return err; - } - } - backlight = of_parse_phandle(dev->of_node, "backlight", 0); if (backlight) { panel->backlight = of_find_backlight_by_node(backlight); @@ -376,6 +369,29 @@ static const struct panel_desc auo_b101xtn01 = { }, }; +static const struct drm_display_mode auo_b116xw03_mode = { + .clock = 70589, + .hdisplay = 1366, + .hsync_start = 1366 + 40, + .hsync_end = 1366 + 40 + 40, + .htotal = 1366 + 40 + 40 + 32, + .vdisplay = 768, + .vsync_start = 768 + 10, + .vsync_end = 768 + 10 + 12, + .vtotal = 768 + 10 + 12 + 6, + .vrefresh = 60, +}; + +static const struct panel_desc auo_b116xw03 = { + .modes = &auo_b116xw03_mode, + .num_modes = 1, + .bpc = 6, + .size = { + .width = 256, + .height = 144, + }, +}; + static const struct drm_display_mode auo_b133xtn01_mode = { .clock = 69500, .hdisplay = 1366, @@ -415,6 +431,7 @@ static const struct drm_display_mode auo_b133htn01_mode = { static const struct panel_desc auo_b133htn01 = { .modes = &auo_b133htn01_mode, .num_modes = 1, + .bpc = 6, .size = { .width = 293, .height = 165, @@ -536,22 +553,92 @@ static const struct drm_display_mode foxlink_fl500wvr00_a0t_mode = { static const struct panel_desc foxlink_fl500wvr00_a0t = { .modes = &foxlink_fl500wvr00_a0t_mode, .num_modes = 1, + .bpc = 8, .size = { .width = 108, .height = 65, }, }; -static const struct drm_display_mode innolux_n116bge_mode = { +static const struct drm_display_mode hannstar_hsd070pww1_mode = { + .clock = 71100, + .hdisplay = 1280, + .hsync_start = 1280 + 1, + .hsync_end = 1280 + 1 + 158, + .htotal = 1280 + 1 + 158 + 1, + .vdisplay = 800, + .vsync_start = 800 + 1, + .vsync_end = 800 + 1 + 21, + .vtotal = 800 + 1 + 21 + 1, + .vrefresh = 60, +}; + +static const struct panel_desc hannstar_hsd070pww1 = { + .modes = &hannstar_hsd070pww1_mode, + .num_modes = 1, + .bpc = 6, + .size = { + .width = 151, + .height = 94, + }, +}; + +static const struct drm_display_mode hitachi_tx23d38vm0caa_mode = { + .clock = 33333, + .hdisplay = 800, + .hsync_start = 800 + 85, + .hsync_end = 800 + 85 + 86, + .htotal = 800 + 85 + 86 + 85, + .vdisplay = 480, + .vsync_start = 480 + 16, + .vsync_end = 480 + 16 + 13, + .vtotal = 480 + 16 + 13 + 16, + .vrefresh = 60, +}; + +static const struct panel_desc hitachi_tx23d38vm0caa = { + .modes = &hitachi_tx23d38vm0caa_mode, + .num_modes = 1, + .bpc = 6, + .size = { + .width = 195, + .height = 117, + }, +}; + +static const struct drm_display_mode innolux_g121i1_l01_mode = { .clock = 71000, + .hdisplay = 1280, + .hsync_start = 1280 + 64, + .hsync_end = 1280 + 64 + 32, + .htotal = 1280 + 64 + 32 + 64, + .vdisplay = 800, + .vsync_start = 800 + 9, + .vsync_end = 800 + 9 + 6, + .vtotal = 800 + 9 + 6 + 9, + .vrefresh = 60, +}; + +static const struct panel_desc innolux_g121i1_l01 = { + .modes = &innolux_g121i1_l01_mode, + .num_modes = 1, + .bpc = 6, + .size = { + .width = 261, + .height = 163, + }, +}; + +static const struct drm_display_mode innolux_n116bge_mode = { + .clock = 76420, .hdisplay = 1366, - .hsync_start = 1366 + 64, - .hsync_end = 1366 + 64 + 6, - .htotal = 1366 + 64 + 6 + 64, + .hsync_start = 1366 + 136, + .hsync_end = 1366 + 136 + 30, + .htotal = 1366 + 136 + 30 + 60, .vdisplay = 768, .vsync_start = 768 + 8, - .vsync_end = 768 + 8 + 4, - .vtotal = 768 + 8 + 4 + 8, + .vsync_end = 768 + 8 + 12, + .vtotal = 768 + 8 + 12 + 12, .vrefresh = 60, .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, }; @@ -643,6 +730,9 @@ static const struct of_device_id platform_of_match[] = { .compatible = "auo,b101xtn01", .data = &auo_b101xtn01, }, { + .compatible = "auo,b116xw03", + .data = &auo_b116xw03, + }, { .compatible = "auo,b133htn01", .data = &auo_b133htn01, }, { @@ -667,6 +757,15 @@ static const struct of_device_id platform_of_match[] = { .compatible = "foxlink,fl500wvr00-a0t", .data = &foxlink_fl500wvr00_a0t, }, { + .compatible = "hannstar,hsd070pww1", + .data = &hannstar_hsd070pww1, + }, { + .compatible = "hit,tx23d38vm0caa", + .data = &hitachi_tx23d38vm0caa + }, { + .compatible ="innolux,g121i1-l01", + .data = &innolux_g121i1_l01 + }, { .compatible = "innolux,n116bge", .data = &innolux_n116bge, }, { @@ -741,6 +840,7 @@ static const struct panel_desc_dsi lg_ld070wx3_sl01 = { .desc = { .modes = &lg_ld070wx3_sl01_mode, .num_modes = 1, + .bpc = 8, .size = { .width = 94, .height = 151, @@ -768,6 +868,7 @@ static const struct panel_desc_dsi lg_lh500wx1_sd03 = { .desc = { .modes = &lg_lh500wx1_sd03_mode, .num_modes = 1, + .bpc = 8, .size = { .width = 62, .height = 110, @@ -795,6 +896,7 @@ static const struct panel_desc_dsi panasonic_vvx10f004b00 = { .desc = { .modes = &panasonic_vvx10f004b00_mode, .num_modes = 1, + .bpc = 8, .size = { .width = 217, .height = 136, |