| .. | .. |
|---|
| 33 | 33 | #include <linux/pm_runtime.h> |
|---|
| 34 | 34 | #include <linux/slab.h> |
|---|
| 35 | 35 | |
|---|
| 36 | +#include <drm/drm_dsc.h> |
|---|
| 37 | +#include <drm/drm_print.h> |
|---|
| 36 | 38 | #include <video/mipi_display.h> |
|---|
| 37 | 39 | |
|---|
| 38 | 40 | /** |
|---|
| .. | .. |
|---|
| 93 | 95 | .pm = &mipi_dsi_device_pm_ops, |
|---|
| 94 | 96 | }; |
|---|
| 95 | 97 | |
|---|
| 96 | | -static int of_device_match(struct device *dev, void *data) |
|---|
| 97 | | -{ |
|---|
| 98 | | - return dev->of_node == data; |
|---|
| 99 | | -} |
|---|
| 100 | | - |
|---|
| 101 | 98 | /** |
|---|
| 102 | 99 | * of_find_mipi_dsi_device_by_node() - find the MIPI DSI device matching a |
|---|
| 103 | 100 | * device tree node |
|---|
| .. | .. |
|---|
| 110 | 107 | { |
|---|
| 111 | 108 | struct device *dev; |
|---|
| 112 | 109 | |
|---|
| 113 | | - dev = bus_find_device(&mipi_dsi_bus_type, NULL, np, of_device_match); |
|---|
| 110 | + dev = bus_find_device_by_of_node(&mipi_dsi_bus_type, np); |
|---|
| 114 | 111 | |
|---|
| 115 | 112 | return dev ? to_mipi_dsi_device(dev) : NULL; |
|---|
| 116 | 113 | } |
|---|
| .. | .. |
|---|
| 159 | 156 | static struct mipi_dsi_device * |
|---|
| 160 | 157 | of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) |
|---|
| 161 | 158 | { |
|---|
| 162 | | - struct device *dev = host->dev; |
|---|
| 163 | 159 | struct mipi_dsi_device_info info = { }; |
|---|
| 164 | 160 | int ret; |
|---|
| 165 | 161 | u32 reg; |
|---|
| 166 | 162 | |
|---|
| 167 | 163 | if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) { |
|---|
| 168 | | - dev_err(dev, "modalias failure on %pOF\n", node); |
|---|
| 164 | + drm_err(host, "modalias failure on %pOF\n", node); |
|---|
| 169 | 165 | return ERR_PTR(-EINVAL); |
|---|
| 170 | 166 | } |
|---|
| 171 | 167 | |
|---|
| 172 | 168 | ret = of_property_read_u32(node, "reg", ®); |
|---|
| 173 | 169 | if (ret) { |
|---|
| 174 | | - dev_err(dev, "device node %pOF has no valid reg property: %d\n", |
|---|
| 170 | + drm_err(host, "device node %pOF has no valid reg property: %d\n", |
|---|
| 175 | 171 | node, ret); |
|---|
| 176 | 172 | return ERR_PTR(-EINVAL); |
|---|
| 177 | 173 | } |
|---|
| .. | .. |
|---|
| 206 | 202 | const struct mipi_dsi_device_info *info) |
|---|
| 207 | 203 | { |
|---|
| 208 | 204 | struct mipi_dsi_device *dsi; |
|---|
| 209 | | - struct device *dev = host->dev; |
|---|
| 210 | 205 | int ret; |
|---|
| 211 | 206 | |
|---|
| 212 | 207 | if (!info) { |
|---|
| 213 | | - dev_err(dev, "invalid mipi_dsi_device_info pointer\n"); |
|---|
| 208 | + drm_err(host, "invalid mipi_dsi_device_info pointer\n"); |
|---|
| 214 | 209 | return ERR_PTR(-EINVAL); |
|---|
| 215 | 210 | } |
|---|
| 216 | 211 | |
|---|
| 217 | 212 | if (info->channel > 3) { |
|---|
| 218 | | - dev_err(dev, "invalid virtual channel: %u\n", info->channel); |
|---|
| 213 | + drm_err(host, "invalid virtual channel: %u\n", info->channel); |
|---|
| 219 | 214 | return ERR_PTR(-EINVAL); |
|---|
| 220 | 215 | } |
|---|
| 221 | 216 | |
|---|
| 222 | 217 | dsi = mipi_dsi_device_alloc(host); |
|---|
| 223 | 218 | if (IS_ERR(dsi)) { |
|---|
| 224 | | - dev_err(dev, "failed to allocate DSI device %ld\n", |
|---|
| 219 | + drm_err(host, "failed to allocate DSI device %ld\n", |
|---|
| 225 | 220 | PTR_ERR(dsi)); |
|---|
| 226 | 221 | return dsi; |
|---|
| 227 | 222 | } |
|---|
| 228 | 223 | |
|---|
| 229 | | - dsi->dev.of_node = info->node; |
|---|
| 224 | + device_set_node(&dsi->dev, of_fwnode_handle(info->node)); |
|---|
| 230 | 225 | dsi->channel = info->channel; |
|---|
| 231 | 226 | strlcpy(dsi->name, info->type, sizeof(dsi->name)); |
|---|
| 232 | 227 | |
|---|
| 233 | 228 | ret = mipi_dsi_device_add(dsi); |
|---|
| 234 | 229 | if (ret) { |
|---|
| 235 | | - dev_err(dev, "failed to add DSI device %d\n", ret); |
|---|
| 230 | + drm_err(host, "failed to add DSI device %d\n", ret); |
|---|
| 236 | 231 | kfree(dsi); |
|---|
| 237 | 232 | return ERR_PTR(ret); |
|---|
| 238 | 233 | } |
|---|
| .. | .. |
|---|
| 305 | 300 | { |
|---|
| 306 | 301 | struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev); |
|---|
| 307 | 302 | |
|---|
| 303 | + mipi_dsi_detach(dsi); |
|---|
| 308 | 304 | mipi_dsi_device_unregister(dsi); |
|---|
| 309 | 305 | |
|---|
| 310 | 306 | return 0; |
|---|
| .. | .. |
|---|
| 379 | 375 | case MIPI_DSI_V_SYNC_END: |
|---|
| 380 | 376 | case MIPI_DSI_H_SYNC_START: |
|---|
| 381 | 377 | case MIPI_DSI_H_SYNC_END: |
|---|
| 378 | + case MIPI_DSI_COMPRESSION_MODE: |
|---|
| 382 | 379 | case MIPI_DSI_END_OF_TRANSMISSION: |
|---|
| 383 | 380 | case MIPI_DSI_COLOR_MODE_OFF: |
|---|
| 384 | 381 | case MIPI_DSI_COLOR_MODE_ON: |
|---|
| .. | .. |
|---|
| 393 | 390 | case MIPI_DSI_DCS_SHORT_WRITE: |
|---|
| 394 | 391 | case MIPI_DSI_DCS_SHORT_WRITE_PARAM: |
|---|
| 395 | 392 | case MIPI_DSI_DCS_READ: |
|---|
| 396 | | - case MIPI_DSI_DCS_COMPRESSION_MODE: |
|---|
| 393 | + case MIPI_DSI_EXECUTE_QUEUE: |
|---|
| 397 | 394 | case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE: |
|---|
| 398 | 395 | return true; |
|---|
| 399 | 396 | } |
|---|
| .. | .. |
|---|
| 412 | 409 | bool mipi_dsi_packet_format_is_long(u8 type) |
|---|
| 413 | 410 | { |
|---|
| 414 | 411 | switch (type) { |
|---|
| 415 | | - case MIPI_DSI_PPS_LONG_WRITE: |
|---|
| 416 | 412 | case MIPI_DSI_NULL_PACKET: |
|---|
| 417 | 413 | case MIPI_DSI_BLANKING_PACKET: |
|---|
| 418 | 414 | case MIPI_DSI_GENERIC_LONG_WRITE: |
|---|
| 419 | 415 | case MIPI_DSI_DCS_LONG_WRITE: |
|---|
| 416 | + case MIPI_DSI_PICTURE_PARAMETER_SET: |
|---|
| 417 | + case MIPI_DSI_COMPRESSED_PIXEL_STREAM: |
|---|
| 420 | 418 | case MIPI_DSI_LOOSELY_PACKED_PIXEL_STREAM_YCBCR20: |
|---|
| 421 | 419 | case MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR24: |
|---|
| 422 | 420 | case MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16: |
|---|
| .. | .. |
|---|
| 551 | 549 | return (ret < 0) ? ret : 0; |
|---|
| 552 | 550 | } |
|---|
| 553 | 551 | EXPORT_SYMBOL(mipi_dsi_set_maximum_return_packet_size); |
|---|
| 552 | + |
|---|
| 553 | +/** |
|---|
| 554 | + * mipi_dsi_compression_mode() - enable/disable DSC on the peripheral |
|---|
| 555 | + * @dsi: DSI peripheral device |
|---|
| 556 | + * @enable: Whether to enable or disable the DSC |
|---|
| 557 | + * |
|---|
| 558 | + * Enable or disable Display Stream Compression on the peripheral using the |
|---|
| 559 | + * default Picture Parameter Set and VESA DSC 1.1 algorithm. |
|---|
| 560 | + * |
|---|
| 561 | + * Return: 0 on success or a negative error code on failure. |
|---|
| 562 | + */ |
|---|
| 563 | +ssize_t mipi_dsi_compression_mode(struct mipi_dsi_device *dsi, bool enable) |
|---|
| 564 | +{ |
|---|
| 565 | + /* Note: Needs updating for non-default PPS or algorithm */ |
|---|
| 566 | + u8 tx[2] = { enable << 0, 0 }; |
|---|
| 567 | + struct mipi_dsi_msg msg = { |
|---|
| 568 | + .channel = dsi->channel, |
|---|
| 569 | + .type = MIPI_DSI_COMPRESSION_MODE, |
|---|
| 570 | + .tx_len = sizeof(tx), |
|---|
| 571 | + .tx_buf = tx, |
|---|
| 572 | + }; |
|---|
| 573 | + int ret = mipi_dsi_device_transfer(dsi, &msg); |
|---|
| 574 | + |
|---|
| 575 | + return (ret < 0) ? ret : 0; |
|---|
| 576 | +} |
|---|
| 577 | +EXPORT_SYMBOL(mipi_dsi_compression_mode); |
|---|
| 578 | + |
|---|
| 579 | +/** |
|---|
| 580 | + * mipi_dsi_picture_parameter_set() - transmit the DSC PPS to the peripheral |
|---|
| 581 | + * @dsi: DSI peripheral device |
|---|
| 582 | + * @pps: VESA DSC 1.1 Picture Parameter Set |
|---|
| 583 | + * |
|---|
| 584 | + * Transmit the VESA DSC 1.1 Picture Parameter Set to the peripheral. |
|---|
| 585 | + * |
|---|
| 586 | + * Return: 0 on success or a negative error code on failure. |
|---|
| 587 | + */ |
|---|
| 588 | +ssize_t mipi_dsi_picture_parameter_set(struct mipi_dsi_device *dsi, |
|---|
| 589 | + const struct drm_dsc_picture_parameter_set *pps) |
|---|
| 590 | +{ |
|---|
| 591 | + struct mipi_dsi_msg msg = { |
|---|
| 592 | + .channel = dsi->channel, |
|---|
| 593 | + .type = MIPI_DSI_PICTURE_PARAMETER_SET, |
|---|
| 594 | + .tx_len = sizeof(*pps), |
|---|
| 595 | + .tx_buf = pps, |
|---|
| 596 | + }; |
|---|
| 597 | + int ret = mipi_dsi_device_transfer(dsi, &msg); |
|---|
| 598 | + |
|---|
| 599 | + return (ret < 0) ? ret : 0; |
|---|
| 600 | +} |
|---|
| 601 | +EXPORT_SYMBOL(mipi_dsi_picture_parameter_set); |
|---|
| 554 | 602 | |
|---|
| 555 | 603 | /** |
|---|
| 556 | 604 | * mipi_dsi_generic_write() - transmit data using a generic write packet |
|---|
| .. | .. |
|---|
| 701 | 749 | { |
|---|
| 702 | 750 | ssize_t err; |
|---|
| 703 | 751 | size_t size; |
|---|
| 752 | + u8 stack_tx[8]; |
|---|
| 704 | 753 | u8 *tx; |
|---|
| 705 | 754 | |
|---|
| 706 | | - if (len > 0) { |
|---|
| 707 | | - size = 1 + len; |
|---|
| 708 | | - |
|---|
| 755 | + size = 1 + len; |
|---|
| 756 | + if (len > ARRAY_SIZE(stack_tx) - 1) { |
|---|
| 709 | 757 | tx = kmalloc(size, GFP_KERNEL); |
|---|
| 710 | 758 | if (!tx) |
|---|
| 711 | 759 | return -ENOMEM; |
|---|
| 712 | | - |
|---|
| 713 | | - /* concatenate the DCS command byte and the payload */ |
|---|
| 714 | | - tx[0] = cmd; |
|---|
| 715 | | - memcpy(&tx[1], data, len); |
|---|
| 716 | 760 | } else { |
|---|
| 717 | | - tx = &cmd; |
|---|
| 718 | | - size = 1; |
|---|
| 761 | + tx = stack_tx; |
|---|
| 719 | 762 | } |
|---|
| 763 | + |
|---|
| 764 | + /* concatenate the DCS command byte and the payload */ |
|---|
| 765 | + tx[0] = cmd; |
|---|
| 766 | + if (data) |
|---|
| 767 | + memcpy(&tx[1], data, len); |
|---|
| 720 | 768 | |
|---|
| 721 | 769 | err = mipi_dsi_dcs_write_buffer(dsi, tx, size); |
|---|
| 722 | 770 | |
|---|
| 723 | | - if (len > 0) |
|---|
| 771 | + if (tx != stack_tx) |
|---|
| 724 | 772 | kfree(tx); |
|---|
| 725 | 773 | |
|---|
| 726 | 774 | return err; |
|---|
| .. | .. |
|---|
| 1096 | 1144 | } |
|---|
| 1097 | 1145 | EXPORT_SYMBOL(mipi_dsi_dcs_get_display_brightness); |
|---|
| 1098 | 1146 | |
|---|
| 1147 | +/** |
|---|
| 1148 | + * mipi_dsi_dcs_set_display_brightness_large() - sets the 16-bit brightness value |
|---|
| 1149 | + * of the display |
|---|
| 1150 | + * @dsi: DSI peripheral device |
|---|
| 1151 | + * @brightness: brightness value |
|---|
| 1152 | + * |
|---|
| 1153 | + * Return: 0 on success or a negative error code on failure. |
|---|
| 1154 | + */ |
|---|
| 1155 | +int mipi_dsi_dcs_set_display_brightness_large(struct mipi_dsi_device *dsi, |
|---|
| 1156 | + u16 brightness) |
|---|
| 1157 | +{ |
|---|
| 1158 | + u8 payload[2] = { brightness >> 8, brightness & 0xff }; |
|---|
| 1159 | + ssize_t err; |
|---|
| 1160 | + |
|---|
| 1161 | + err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_BRIGHTNESS, |
|---|
| 1162 | + payload, sizeof(payload)); |
|---|
| 1163 | + if (err < 0) |
|---|
| 1164 | + return err; |
|---|
| 1165 | + |
|---|
| 1166 | + return 0; |
|---|
| 1167 | +} |
|---|
| 1168 | +EXPORT_SYMBOL(mipi_dsi_dcs_set_display_brightness_large); |
|---|
| 1169 | + |
|---|
| 1170 | +/** |
|---|
| 1171 | + * mipi_dsi_dcs_get_display_brightness_large() - gets the current 16-bit |
|---|
| 1172 | + * brightness value of the display |
|---|
| 1173 | + * @dsi: DSI peripheral device |
|---|
| 1174 | + * @brightness: brightness value |
|---|
| 1175 | + * |
|---|
| 1176 | + * Return: 0 on success or a negative error code on failure. |
|---|
| 1177 | + */ |
|---|
| 1178 | +int mipi_dsi_dcs_get_display_brightness_large(struct mipi_dsi_device *dsi, |
|---|
| 1179 | + u16 *brightness) |
|---|
| 1180 | +{ |
|---|
| 1181 | + u8 brightness_be[2]; |
|---|
| 1182 | + ssize_t err; |
|---|
| 1183 | + |
|---|
| 1184 | + err = mipi_dsi_dcs_read(dsi, MIPI_DCS_GET_DISPLAY_BRIGHTNESS, |
|---|
| 1185 | + brightness_be, sizeof(brightness_be)); |
|---|
| 1186 | + if (err <= 0) { |
|---|
| 1187 | + if (err == 0) |
|---|
| 1188 | + err = -ENODATA; |
|---|
| 1189 | + |
|---|
| 1190 | + return err; |
|---|
| 1191 | + } |
|---|
| 1192 | + |
|---|
| 1193 | + *brightness = (brightness_be[0] << 8) | brightness_be[1]; |
|---|
| 1194 | + |
|---|
| 1195 | + return 0; |
|---|
| 1196 | +} |
|---|
| 1197 | +EXPORT_SYMBOL(mipi_dsi_dcs_get_display_brightness_large); |
|---|
| 1198 | + |
|---|
| 1099 | 1199 | static int mipi_dsi_drv_probe(struct device *dev) |
|---|
| 1100 | 1200 | { |
|---|
| 1101 | 1201 | struct mipi_dsi_driver *drv = to_mipi_dsi_driver(dev->driver); |
|---|