diff options
author | Dave Airlie <airlied@redhat.com> | 2022-02-25 05:30:17 +1000 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2022-02-25 05:50:18 +1000 |
commit | 54f43c17d681f6d9523fcfaeefc9df77993802e1 (patch) | |
tree | a1b3807e26d05b9b17aea43b7725caf3757522ca /drivers/gpu/drm/drm_fb_helper.c | |
parent | 7f44571b53fd07e36ae4d2537a6fb40d79b39462 (diff) | |
parent | f915686bd97a9c234602426e6d132b74a112a8d6 (diff) | |
download | linux-54f43c17d681f6d9523fcfaeefc9df77993802e1.tar.gz linux-54f43c17d681f6d9523fcfaeefc9df77993802e1.tar.bz2 linux-54f43c17d681f6d9523fcfaeefc9df77993802e1.zip |
Merge tag 'drm-misc-next-2022-02-23' of git://anongit.freedesktop.org/drm/drm-misc into drm-next
drm-misc-next for v5.18:
UAPI Changes:
Cross-subsystem Changes:
- Split out panel-lvds and lvds dt bindings .
- Put yes/no on/off disabled/enabled strings in linux/string_helpers.h
and use it in drivers and tomoyo.
- Clarify dma_fence_chain and dma_fence_array should never include eachother.
- Flatten chains in syncobj's.
- Don't double add in fbdev/defio when page is already enlisted.
- Don't sort deferred-I/O pages by default in fbdev.
Core Changes:
- Fix missing pm_runtime_put_sync in bridge.
- Set modifier support to only linear fb modifier if drivers don't
advertise support.
- As a result, we remove allow_fb_modifiers.
- Add missing clear for EDID Deep Color Modes in drm_reset_display_info.
- Assorted documentation updates.
- Warn once in drm_clflush if there is no arch support.
- Add missing select for dp helper in drm_panel_edp.
- Assorted small fixes.
- Improve fb-helper's clipping handling.
- Don't dump shmem mmaps in a core dump.
- Add accounting to ttm resource manager, and use it in amdgpu.
- Allow querying the detected eDP panel through debugfs.
- Add helpers for xrgb8888 to 8 and 1 bits gray.
- Improve drm's buddy allocator.
- Add selftests for the buddy allocator.
Driver Changes:
- Add support for nomodeset to a lot of drm drivers.
- Use drm_module_*_driver in a lot of drm drivers.
- Assorted small fixes to bridge/lt9611, v3d, vc4, vmwgfx, mxsfb, nouveau,
bridge/dw-hdmi, panfrost, lima, ingenic, sprd, bridge/anx7625, ti-sn65dsi86.
- Add bridge/it6505.
- Create DP and DVI-I connectors in ast.
- Assorted nouveau backlight fixes.
- Rework amdgpu reset handling.
- Add dt bindings for ingenic,jz4780-dw-hdmi.
- Support reading edid through aux channel in ingenic.
- Add a drm driver for Solomon SSD130x OLED displays.
- Add simple support for sharp LQ140M1JW46.
- Add more panels to nt35560.
Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/686ec871-e77f-c230-22e5-9e3bb80f064a@linux.intel.com
Diffstat (limited to 'drivers/gpu/drm/drm_fb_helper.c')
-rw-r--r-- | drivers/gpu/drm/drm_fb_helper.c | 78 |
1 files changed, 60 insertions, 18 deletions
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 6f72627369f8..d265a73313c9 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -680,6 +680,31 @@ static void drm_fb_helper_damage(struct fb_info *info, u32 x, u32 y, schedule_work(&helper->damage_work); } +/* Convert memory region into area of scanlines and pixels per scanline */ +static void drm_fb_helper_memory_range_to_clip(struct fb_info *info, off_t off, size_t len, + struct drm_rect *clip) +{ + off_t end = off + len; + u32 x1 = 0; + u32 y1 = off / info->fix.line_length; + u32 x2 = info->var.xres; + u32 y2 = DIV_ROUND_UP(end, info->fix.line_length); + + if ((y2 - y1) == 1) { + /* + * We've only written to a single scanline. Try to reduce + * the number of horizontal pixels that need an update. + */ + off_t bit_off = (off % info->fix.line_length) * 8; + off_t bit_end = (end % info->fix.line_length) * 8; + + x1 = bit_off / info->var.bits_per_pixel; + x2 = DIV_ROUND_UP(bit_end, info->var.bits_per_pixel); + } + + drm_rect_init(clip, x1, y1, x2 - x1, y2 - y1); +} + /** * drm_fb_helper_deferred_io() - fbdev deferred_io callback function * @info: fb_info struct pointer @@ -693,23 +718,23 @@ void drm_fb_helper_deferred_io(struct fb_info *info, { unsigned long start, end, min, max; struct page *page; - u32 y1, y2; + struct drm_rect damage_area; min = ULONG_MAX; max = 0; list_for_each_entry(page, pagelist, lru) { start = page->index << PAGE_SHIFT; - end = start + PAGE_SIZE - 1; + end = start + PAGE_SIZE; min = min(min, start); max = max(max, end); } + if (min >= max) + return; - if (min < max) { - y1 = min / info->fix.line_length; - y2 = min_t(u32, DIV_ROUND_UP(max, info->fix.line_length), - info->var.yres); - drm_fb_helper_damage(info, 0, y1, info->var.xres, y2 - y1); - } + drm_fb_helper_memory_range_to_clip(info, min, max - min, &damage_area); + drm_fb_helper_damage(info, damage_area.x1, damage_area.y1, + drm_rect_width(&damage_area), + drm_rect_height(&damage_area)); } EXPORT_SYMBOL(drm_fb_helper_deferred_io); @@ -741,11 +766,18 @@ EXPORT_SYMBOL(drm_fb_helper_sys_read); ssize_t drm_fb_helper_sys_write(struct fb_info *info, const char __user *buf, size_t count, loff_t *ppos) { + loff_t pos = *ppos; ssize_t ret; + struct drm_rect damage_area; ret = fb_sys_write(info, buf, count, ppos); - if (ret > 0) - drm_fb_helper_damage(info, 0, 0, info->var.xres, info->var.yres); + if (ret <= 0) + return ret; + + drm_fb_helper_memory_range_to_clip(info, pos, ret, &damage_area); + drm_fb_helper_damage(info, damage_area.x1, damage_area.y1, + drm_rect_width(&damage_area), + drm_rect_height(&damage_area)); return ret; } @@ -2224,6 +2256,7 @@ static ssize_t drm_fbdev_fb_write(struct fb_info *info, const char __user *buf, loff_t pos = *ppos; size_t total_size; ssize_t ret; + struct drm_rect damage_area; int err = 0; if (info->screen_size) @@ -2252,13 +2285,19 @@ static ssize_t drm_fbdev_fb_write(struct fb_info *info, const char __user *buf, else ret = fb_write_screen_buffer(info, buf, count, pos); - if (ret > 0) - *ppos += ret; + if (ret < 0) + return ret; /* return last error, if any */ + else if (!ret) + return err; /* return previous error, if any */ - if (ret > 0) - drm_fb_helper_damage(info, 0, 0, info->var.xres_virtual, info->var.yres_virtual); + *ppos += ret; - return ret ? ret : err; + drm_fb_helper_memory_range_to_clip(info, pos, ret, &damage_area); + drm_fb_helper_damage(info, damage_area.x1, damage_area.y1, + drm_rect_width(&damage_area), + drm_rect_height(&damage_area)); + + return ret; } static void drm_fbdev_fb_fillrect(struct fb_info *info, @@ -2346,6 +2385,7 @@ static int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper, fbi->fbops = &drm_fbdev_fb_ops; fbi->screen_size = sizes->surface_height * fb->pitches[0]; fbi->fix.smem_len = fbi->screen_size; + fbi->flags = FBINFO_DEFAULT; drm_fb_helper_fill_info(fbi, fb_helper, sizes); @@ -2353,19 +2393,21 @@ static int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper, fbi->screen_buffer = vzalloc(fbi->screen_size); if (!fbi->screen_buffer) return -ENOMEM; + fbi->flags |= FBINFO_VIRTFB | FBINFO_READS_FAST; fbi->fbdefio = &drm_fbdev_defio; - fb_deferred_io_init(fbi); } else { /* buffer is mapped for HW framebuffer */ ret = drm_client_buffer_vmap(fb_helper->buffer, &map); if (ret) return ret; - if (map.is_iomem) + if (map.is_iomem) { fbi->screen_base = map.vaddr_iomem; - else + } else { fbi->screen_buffer = map.vaddr; + fbi->flags |= FBINFO_VIRTFB; + } /* * Shamelessly leak the physical address to user-space. As |