| From fca6519395301cee8dce07d15121c8b5c551ec6b Mon Sep 17 00:00:00 2001 |
| From: Douglas Anderson <dianders@chromium.org> |
| Date: Fri, 18 Oct 2019 13:05:07 -0700 |
| Subject: [PATCH] CHROMIUM: drm/udl: Implement cursor. |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| BUG=b:328264482,b:328419768,chromium:1015951 |
| UPSTREAM-TASK=b:375004557 |
| TEST=Tested on brya board and intell with Ubuntu 22.04 with kernel 6.5 |
| |
| Cherry-pick-signed-off-by: Haixia Shi <hshi@chromium.org> |
| Cherry-Pick-Change-Id: Ib6531aab4bd3590b431dd4e2517974db0c02769b |
| (cherry picked from commit e93ad1bb5cb2d295fdd46c99f105a2dbaceb0595) |
| Signed-off-by: Ross Zwisler <zwisler@google.com> |
| Reviewed-on: https://chromium-review.googlesource.com/1854365 |
| Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com> |
| Legacy-Commit-Queue: Commit Bot <commit-bot@chromium.org> |
| Reviewed-by: Daniele Castagna <dcastagna@chromium.org> |
| (cherry picked from commit 1053f4d505f82d8033d2117e8fbd5d118b5b3ab0) |
| [dianders resolved with commit c2f53119b410 ("udl-kms: use |
| spin_lock_irq instead of spin_lock_irqsave") |
| Signed-off-by: Douglas Anderson <dianders@chromium.org> |
| Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1869494 |
| Reviewed-by: Robert Tarasov <tutankhamen@chromium.org> |
| |
| [rebase54(groeck): Context conflicts; |
| drm_gem_object_unreference -> drm_gem_object_put] |
| |
| Cherry-Pick-Change_Id: I9dded25dab38bcdb277736a37f4f3258003db097 |
| Cherry-pick-signed-off-by: Guenter Roeck <groeck@chromium.org> |
| |
| Port to kernel to latest upstream kernel where udl is atomic driver without legacy cursor ioctls' |
| - removed old udl_cursor_move, udl_cursor_set ioctl's implementation |
| - modified udl_cursor_download to copy cursor content to the buffer from iosys_map |
| - removed unnecessary cursor copy in udl_handle_damage |
| - simplify code by making struct udl_cursor public |
| |
| (cherry picked from commit efb4c23afa3e1de185a1a4f8ff5b7ec412aec0fe) |
| |
| Change-Id: I806a5494a85166aebd74f37c54b2a3f29e212618 |
| Signed-off-by: Guenter Roeck <groeck@chromium.org> |
| Signed-off-by: Łukasz Spintzyk <Lukasz.Spintzyk@synaptics.com> |
| Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/5954345 |
| Tested-by: Łukasz Spintzyk <lukasz.spintzyk@synaptics.com> |
| Commit-Queue: Łukasz Spintzyk <lukasz.spintzyk@synaptics.com> |
| Reviewed-by: Dominik Behr <dbehr@chromium.org> |
| Reviewed-by: Łukasz Spintzyk <lukasz.spintzyk@synaptics.com> |
| Auto-Submit: Łukasz Spintzyk <lukasz.spintzyk@synaptics.com> |
| --- |
| drivers/gpu/drm/udl/Makefile | 8 +-- |
| drivers/gpu/drm/udl/udl_cursor.c | 78 ++++++++++++++++++++++++++++++ |
| drivers/gpu/drm/udl/udl_cursor.h | 47 ++++++++++++++++++ |
| drivers/gpu/drm/udl/udl_drv.h | 6 ++- |
| drivers/gpu/drm/udl/udl_modeset.c | 9 +++- |
| drivers/gpu/drm/udl/udl_transfer.c | 36 +++++++++++++- |
| 6 files changed, 173 insertions(+), 11 deletions(-) |
| create mode 100644 drivers/gpu/drm/udl/udl_cursor.c |
| create mode 100644 drivers/gpu/drm/udl/udl_cursor.h |
| |
| diff --git a/drivers/gpu/drm/udl/Makefile b/drivers/gpu/drm/udl/Makefile |
| index 43d69a16af183bc7271e99125cb28f69b0d51349..0abd04b0e829163d13ced69ab0ade3d6fe4d8c87 100644 |
| --- a/drivers/gpu/drm/udl/Makefile |
| +++ b/drivers/gpu/drm/udl/Makefile |
| @@ -1,10 +1,4 @@ |
| # SPDX-License-Identifier: GPL-2.0-only |
| - |
| -udl-y := \ |
| - udl_drv.o \ |
| - udl_edid.o \ |
| - udl_main.o \ |
| - udl_modeset.o \ |
| - udl_transfer.o |
| +udl-y := udl_drv.o udl_modeset.o udl_main.o udl_transfer.o udl_cursor.o |
| |
| obj-$(CONFIG_DRM_UDL) := udl.o |
| diff --git a/drivers/gpu/drm/udl/udl_cursor.c b/drivers/gpu/drm/udl/udl_cursor.c |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..594bb3b6b056c9e2501c4592552252d5048caf77 |
| --- /dev/null |
| +++ b/drivers/gpu/drm/udl/udl_cursor.c |
| @@ -0,0 +1,78 @@ |
| +// SPDX-License-Identifier: GPL-2.0-or-later |
| +/* |
| + * udl_cursor.c |
| + * |
| + * Copyright (c) 2015 The Chromium OS Authors |
| + * |
| + * This program is free software; you can redistribute it and/or modify it |
| + * under the terms of the GNU General Public License as published by the |
| + * Free Software Foundation; either version 2 of the License, or (at your |
| + * option) any later version. |
| + * |
| + * This program is distributed in the hope that it will be useful, |
| + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + * GNU General Public License for more details. |
| + * |
| + * You should have received a copy of the GNU General Public License |
| + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| + */ |
| +#include <linux/iosys-map.h> |
| +#include <drm/drm_crtc_helper.h> |
| + |
| +#include "udl_cursor.h" |
| +#include "udl_drv.h" |
| + |
| +void udl_cursor_get_hline(struct udl_cursor *cursor, int x, int y, |
| + struct udl_cursor_hline *hline) |
| +{ |
| + if (!cursor || !cursor->enabled || |
| + x >= cursor->x + UDL_CURSOR_W || |
| + y < cursor->y || y >= cursor->y + UDL_CURSOR_H) { |
| + hline->buffer = NULL; |
| + return; |
| + } |
| + |
| + hline->buffer = &cursor->buffer[UDL_CURSOR_W * (y - cursor->y)]; |
| + hline->width = UDL_CURSOR_W; |
| + hline->offset = x - cursor->x; |
| +} |
| + |
| +/* |
| + * Return pre-computed cursor blend value defined as: |
| + * R: 5 bits (bit 0:4) |
| + * G: 6 bits (bit 5:10) |
| + * B: 5 bits (bit 11:15) |
| + * A: 7 bits (bit 16:22) |
| + */ |
| +static uint32_t cursor_blend_val32(uint32_t pix) |
| +{ |
| + /* range of alpha_scaled is 0..64 */ |
| + uint32_t alpha_scaled = ((pix >> 24) * 65) >> 8; |
| + |
| + return ((pix >> 3) & 0x1f) | |
| + ((pix >> 5) & 0x7e0) | |
| + ((pix >> 8) & 0xf800) | |
| + (alpha_scaled << 16); |
| +} |
| + |
| +int udl_cursor_download(struct udl_cursor *cursor, |
| + const struct iosys_map *map) |
| +{ |
| + uint32_t *src_ptr, *dst_ptr; |
| + size_t i; |
| + |
| + src_ptr = map->vaddr; |
| + dst_ptr = cursor->buffer; |
| + for (i = 0; i < UDL_CURSOR_BUF; ++i) |
| + dst_ptr[i] = cursor_blend_val32(le32_to_cpu(src_ptr[i])); |
| + return 0; |
| +} |
| + |
| + |
| +int udl_cursor_move(struct udl_cursor *cursor, int x, int y) |
| +{ |
| + cursor->x = x; |
| + cursor->y = y; |
| + return 0; |
| +} |
| diff --git a/drivers/gpu/drm/udl/udl_cursor.h b/drivers/gpu/drm/udl/udl_cursor.h |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..6a848accc106d85fadcce450b64d1bbd284eec1c |
| --- /dev/null |
| +++ b/drivers/gpu/drm/udl/udl_cursor.h |
| @@ -0,0 +1,47 @@ |
| +/* SPDX-License-Identifier: GPL-2.0-or-later |
| + * |
| + * udl_cursor.h |
| + * |
| + * Copyright (c) 2015 The Chromium OS Authors |
| + * |
| + * This program is free software; you can redistribute it and/or modify it |
| + * under the terms of the GNU General Public License as published by the |
| + * Free Software Foundation; either version 2 of the License, or (at your |
| + * option) any later version. |
| + * |
| + * This program is distributed in the hope that it will be useful, |
| + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| + * GNU General Public License for more details. |
| + * |
| + * You should have received a copy of the GNU General Public License |
| + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| + */ |
| + |
| +#ifndef _UDL_CURSOR_H_ |
| +#define _UDL_CURSOR_H_ |
| + |
| +#include <linux/module.h> |
| +#include <drm/drm_crtc.h> |
| + |
| +#define UDL_CURSOR_W 64 |
| +#define UDL_CURSOR_H 64 |
| +#define UDL_CURSOR_BUF (UDL_CURSOR_W * UDL_CURSOR_H) |
| +struct udl_cursor { |
| + uint32_t buffer[UDL_CURSOR_BUF]; |
| + bool enabled; |
| + int x; |
| + int y; |
| +}; |
| +struct udl_cursor_hline { |
| + uint32_t *buffer; |
| + int width; |
| + int offset; |
| +}; |
| + |
| +extern void udl_cursor_get_hline(struct udl_cursor *cursor, int x, int y, |
| + struct udl_cursor_hline *hline); |
| +extern int udl_cursor_move(struct udl_cursor *cursor, int x, int y); |
| +extern int udl_cursor_download(struct udl_cursor *cursor, const struct iosys_map *map); |
| + |
| +#endif |
| diff --git a/drivers/gpu/drm/udl/udl_drv.h b/drivers/gpu/drm/udl/udl_drv.h |
| index 1eb716d9dad571dd4a7d8f5765fb69663786bf61..6245e416177e32ec35833123fd70e80480b7699d 100644 |
| --- a/drivers/gpu/drm/udl/udl_drv.h |
| +++ b/drivers/gpu/drm/udl/udl_drv.h |
| @@ -21,6 +21,7 @@ |
| #include <drm/drm_framebuffer.h> |
| #include <drm/drm_gem.h> |
| #include <drm/drm_plane.h> |
| +#include "udl_cursor.h" |
| |
| struct drm_mode_create_dumb; |
| |
| @@ -49,6 +50,7 @@ struct urb_list { |
| size_t size; |
| }; |
| |
| +struct udl_cursor_hline; |
| struct udl_device { |
| struct drm_device drm; |
| struct device *dev; |
| @@ -64,6 +66,7 @@ struct udl_device { |
| int sku_pixel_limit; |
| |
| struct urb_list urbs; |
| + struct udl_cursor cursor; |
| }; |
| |
| #define to_udl(x) container_of(x, struct udl_device, drm) |
| @@ -87,7 +90,8 @@ int udl_init(struct udl_device *udl); |
| |
| int udl_render_hline(struct drm_device *dev, int log_bpp, struct urb **urb_ptr, |
| const char *front, char **urb_buf_ptr, |
| - u32 byte_offset, u32 device_byte_offset, u32 byte_width); |
| + u32 byte_offset, u32 device_byte_offset, u32 byte_width, |
| + struct udl_cursor_hline *cursor_hline); |
| |
| int udl_drop_usb(struct drm_device *dev); |
| int udl_select_std_channel(struct udl_device *udl); |
| diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c |
| index 2a12407078b55cd30b7f45dffa9dfe8d15ff1eef..bcb8fcc65eea294acce1e134c96750bc9fe5ec84 100644 |
| --- a/drivers/gpu/drm/udl/udl_modeset.c |
| +++ b/drivers/gpu/drm/udl/udl_modeset.c |
| @@ -27,6 +27,9 @@ |
| #include "udl_drv.h" |
| #include "udl_edid.h" |
| #include "udl_proto.h" |
| +#include "udl_cursor.h" |
| + |
| +#define UDL_COLOR_DEPTH_16BPP 0 |
| |
| /* |
| * All DisplayLink bulk operations start with 0xaf (UDL_MSG_BULK), followed by |
| @@ -205,6 +208,7 @@ static int udl_handle_damage(struct drm_framebuffer *fb, |
| const struct drm_rect *clip) |
| { |
| struct drm_device *dev = fb->dev; |
| + struct udl_device *udl = to_udl(dev); |
| void *vaddr = map->vaddr; /* TODO: Use mapping abstraction properly */ |
| int i, ret; |
| char *cmd; |
| @@ -226,9 +230,12 @@ static int udl_handle_damage(struct drm_framebuffer *fb, |
| const int byte_offset = line_offset + (clip->x1 << log_bpp); |
| const int dev_byte_offset = (fb->width * i + clip->x1) << log_bpp; |
| const int byte_width = drm_rect_width(clip) << log_bpp; |
| + struct udl_cursor_hline cursor_hline; |
| + |
| + udl_cursor_get_hline(&udl->cursor, clip->x1, i, &cursor_hline); |
| ret = udl_render_hline(dev, log_bpp, &urb, (char *)vaddr, |
| &cmd, byte_offset, dev_byte_offset, |
| - byte_width); |
| + byte_width, &cursor_hline); |
| if (ret) |
| return ret; |
| } |
| diff --git a/drivers/gpu/drm/udl/udl_transfer.c b/drivers/gpu/drm/udl/udl_transfer.c |
| index 62224992988f283e9c896bf7bf440cbf366ac282..c17e722edb56b8fd3ee35203478098dcae0c4c5b 100644 |
| --- a/drivers/gpu/drm/udl/udl_transfer.c |
| +++ b/drivers/gpu/drm/udl/udl_transfer.c |
| @@ -11,6 +11,7 @@ |
| |
| #include "udl_drv.h" |
| #include "udl_proto.h" |
| +#include "udl_cursor.h" |
| |
| #define MAX_CMD_PIXELS 255 |
| |
| @@ -43,6 +44,19 @@ static inline u16 get_pixel_val16(const uint8_t *pixel, int log_bpp) |
| return pixel_val16; |
| } |
| |
| +static inline u16 blend_alpha(const uint16_t pixel_val16, uint32_t blend_val32) |
| +{ |
| + uint32_t alpha = (blend_val32 >> 16); |
| + uint32_t alpha_inv = 64 - alpha; |
| + |
| + return (((pixel_val16 & 0x1f) * alpha_inv + |
| + (blend_val32 & 0x1f) * alpha) >> 6) | |
| + ((((pixel_val16 & 0x7e0) * alpha_inv + |
| + (blend_val32 & 0x7e0) * alpha) >> 6) & 0x7e0) | |
| + ((((pixel_val16 & 0xf800) * alpha_inv + |
| + (blend_val32 & 0xf800) * alpha) >> 6) & 0xf800); |
| +} |
| + |
| /* |
| * Render a command stream for an encoded horizontal line segment of pixels. |
| * |
| @@ -74,6 +88,7 @@ static void udl_compress_hline16( |
| const u8 **pixel_start_ptr, |
| const u8 *const pixel_end, |
| uint32_t *device_address_ptr, |
| + struct udl_cursor_hline *cursor_hline, |
| uint8_t **command_buffer_ptr, |
| const uint8_t *const cmd_buffer_end, int log_bpp) |
| { |
| @@ -81,6 +96,9 @@ static void udl_compress_hline16( |
| const u8 *pixel = *pixel_start_ptr; |
| uint32_t dev_addr = *device_address_ptr; |
| uint8_t *cmd = *command_buffer_ptr; |
| + const uint32_t *cursor_buf = cursor_hline ? cursor_hline->buffer : NULL; |
| + int cursor_pos = cursor_buf ? cursor_hline->offset : 0; |
| + int cursor_width = cursor_buf ? cursor_hline->width : 0; |
| |
| while ((pixel_end > pixel) && |
| (cmd_buffer_end - MIN_RLX_CMD_BYTES > cmd)) { |
| @@ -107,6 +125,11 @@ static void udl_compress_hline16( |
| (unsigned long)(cmd_buffer_end - 1 - cmd) / 2) << log_bpp); |
| |
| pixel_val16 = get_pixel_val16(pixel, log_bpp); |
| + if (cursor_buf && cursor_pos >= 0 && |
| + cursor_pos < cursor_width) { |
| + pixel_val16 = blend_alpha(pixel_val16, |
| + cursor_buf[cursor_pos]); |
| + } |
| |
| while (pixel < cmd_pixel_end) { |
| const u8 *const start = pixel; |
| @@ -116,12 +139,19 @@ static void udl_compress_hline16( |
| |
| cmd += 2; |
| pixel += bpp; |
| + cursor_pos++; |
| |
| while (pixel < cmd_pixel_end) { |
| pixel_val16 = get_pixel_val16(pixel, log_bpp); |
| + if (cursor_buf && cursor_pos >= 0 && |
| + cursor_pos < cursor_width) { |
| + pixel_val16 = blend_alpha(pixel_val16, |
| + cursor_buf[cursor_pos]); |
| + } |
| if (pixel_val16 != repeating_pixel_val16) |
| break; |
| pixel += bpp; |
| + cursor_pos++; |
| } |
| |
| if (unlikely(pixel > start + bpp)) { |
| @@ -160,6 +190,8 @@ static void udl_compress_hline16( |
| *command_buffer_ptr = cmd; |
| *pixel_start_ptr = pixel; |
| *device_address_ptr = dev_addr; |
| + if (cursor_buf) |
| + cursor_hline->offset = cursor_pos; |
| |
| return; |
| } |
| @@ -173,7 +205,7 @@ static void udl_compress_hline16( |
| int udl_render_hline(struct drm_device *dev, int log_bpp, struct urb **urb_ptr, |
| const char *front, char **urb_buf_ptr, |
| u32 byte_offset, u32 device_byte_offset, |
| - u32 byte_width) |
| + u32 byte_width, struct udl_cursor_hline *cursor_hline) |
| { |
| const u8 *line_start, *line_end, *next_pixel; |
| u32 base16 = 0 + (device_byte_offset >> log_bpp) * 2; |
| @@ -194,7 +226,7 @@ int udl_render_hline(struct drm_device *dev, int log_bpp, struct urb **urb_ptr, |
| while (next_pixel < line_end) { |
| |
| udl_compress_hline16(&next_pixel, |
| - line_end, &base16, |
| + line_end, &base16, cursor_hline, |
| (u8 **) &cmd, (u8 *) cmd_end, log_bpp); |
| |
| if (cmd >= cmd_end) { |
| -- |
| 2.47.0.163.g1226f6d8fa-goog |
| |