.. | .. |
---|
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); |
---|