mirror of
https://github.com/torvalds/linux.git
synced 2024-12-03 17:41:22 +00:00
b3ce7a3084
core: - deprecate DRM data and return 0 date - connector: Create a set of helpers to help with HDMI support - Remove driver owner assignments - Allow more drivers to compile with COMPILE_TEST - Conversions to drm_edid - Sprinkle MODULE_DESCRIPTIONS everywhere they are missing - Remove drm_mm_replace_node - print: Add a drm prefix to warn level messages too, remove ___drm_dbg, consolidate prefix handling - New monochrome TV mode variant ttm: - improve number of page faults on some platforms - fix test builds under PREEMPT_RT - more test coverage ci: - Require a more recent version of mesa, - improve farm setup and test generation dma-buf: - warn if reserving 0 fence slots - internal API heap enhancements fbdev: - Create memory manager optimized fbdev emulation panic: - Allow to select fonts, - improve drm_fb_dma_get_scanout_buffer - Allow to dump kmsg to the screen bridge: - Remove redundant checks on bridge->encoder - Remove drm_bridge_chain_mode_fixup - bridge-connector: Plumb in the new HDMI helper - analogix_dp: Various improvements, handle AUX transfers timeout - samsung-dsim: Fix timings calculation - tc358767: Plenty of small fixes, fix no connector attach, fix clocks - sii902x: state validation improvements panels: - Switch panels from register table initialization to proper code - Now that the panel code tracks the panel state, remove every ad-hoc implementation in the panel drivers - More cleanup of prepare / enable state tracking in drivers - edp: Drop legacy panel compatibles - simple-bridge: Switch to devm_drm_bridge_add - New panels: Lincoln Tech Sol LCD185-101CT, Microtips Technology 13-101HIEBCAF0-C, Microtips Technology MF-103HIEB0GA0, BOE nv110wum-l60, IVO t109nw41, WL-355608-A8, PrimeView PM070WL4, Lincoln Technologies LCD197, Ortustech COM35H3P70ULC, AUO G104STN01, K&d kd101ne3-40ti amdgpu: - DCN 4.0.x support - GC 12.0 support - GMC 12.0 support - SDMA 7.0 support - MES12 support - MMHUB 4.1 support - GFX12 modifier and DCC support - lots of IP fixes/updates amdkfd: - Contiguous VRAM allocations - GC 12.0 support - SDMA 7.0 support - SR-IOV fixes - KFD GFX ALU exceptions i915: - Battlemage Xe2 HPD display enablement - Panel Replay enabling - DP AUX-less ALPM/LOBF - Enable link training failure fallback for DP MST links - CMRR (Content Match Refresh Rate) enabling - Increase ADL-S/ADL-P/DG2+ max TMDS bitrate to 6 Gbps - Enable eDP AUX based HDR backlight - Support replaying GPU hangs with captured context image - Automate CCS Mode setting during engine resets - lots of refactoring - Support replaying GPU hangs with captured context image - Increase FLR timeout from 3s to 9s - Enable w/a 16021333562 for DG2, MTL and ARL [guc] xe: - update MAINATINERS - New uapi adding OA functionality to Xe - expose l3 bank mask - fix display detect on ADL-N - runtime PM Fixes - Fix silent backmerge issues - More prep for SR-IOV - HWmon additions - per client usage info - Rework GPU page fault handling - Drop EXEC_QUEUE_FLAG_BANNED - Add BMG PCI IDs - Scheduler fixes and improvements - Rename xe_exec_queue::compute to xe_exec_queue::lr - Use ttm_uncached for BO with NEEDS_UC flag - Rename xe perf layer as xe observation layer - lots of refactoring radeon: - Backlight workaround for iMac - Silence UBSAN flex array warnings msm: - Validate registers XML description against schema in CI - core/dpu: SM7150 support - mdp5: Add support for MSM8937 - gpu: Add param for userspace to know if raytracing is supported - gpu: X185 support (aka gpu in X1 laptop chips) - gpu: a505 support ivpu: - hardware scheduler support - profiling support - improvements to the platform support layer - firmware handling improvements - clocks/power mgmt improvements - scheduler/logging improvements habanalabs: - Gradual sleep in polling memory macro. - Reduce Gaudi2 MSI-X interrupt count to 128. - Add Gaudi2-D revision support. - Add timestamp to CPLD info. - Gaudi2: Assume hard-reset by firmware upon MC SEI severe error. - Align Gaudi2 interrupt names. - Check for errors after preboot is ready. - Change habanalabs maintainer and git repo path. mgag200: - refactoring and improvements - Add BMC output - enable polling nouveau: - add registry command line v3d: - perf counters improvements zynqmp: - irq and debugfs improvements atmel-hlcdc: - Support XLCDC in sam9x7 mipi-dbi: - Remove mipi_dbi_machine_little_endian - make SPI bits per word configurable - support RGB888 - allow pixel formats to be specified in the DT sun4i: - Rework the blender setup for DE2 panfrost: - Enable MT8188 support vc4: - Monochrome TV support exynos: - fix fallback mode regression - fix memory leak - Use drm_edid_duplicate() instead of kmemdup() etnaviv: - fix i.MX8MP NPU clock gating - workaround FE register cdc issues on some cores - fix DMA sync handling for cached buffers - fix job timeout handling - keep TS enabled on MMUv2 cores for improved performance mediatek: - Convert to platform remove callback returning void- - Drop chain_mode_fixup call in mode_valid() - Fixes the errors of MediaTek display driver found by IGT. - Add display support for the MT8365-EVK board - Fix bit depth overwritten for mtk_ovl_set bit_depth() - Fix possible_crtcs calculation - Fix spurious kfree() ast: - refactor mode setting code stm: - Add LVDS support - DSI PHY updates -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEEKbZHaGwW9KfbeusDHTzWXnEhr4FAmaYqVEACgkQDHTzWXnE hr5p3Q/+OOxTHKJ/8WMwfV1Tuep5otkCZdBgNdcuu9zqzpEMEDUDwmV1iboIvT9x qJsDwSAJomwbZAnVjDKsbZuycSHUBV6HQdf+5+rtq6be1EfFRwJVzOq0u5+D3KGt 7f2vy6sM9tw4tR6EikiuP7vCvnSz4iGrWERvEJDEtXECbALhju8sulht8ZMnr6GW /MfUetULLSDjq0L1x3TWAq2MPGnJ5UxIkIeOBUP6n4etAUX1BPTNA6N76eN/xMvn a40JhtM+pCjjkHxvloIZ+KTYN3S+hskIRksczPHh9HtNX7y/A437wyhOHJZ1NvZb yc5ke9GjXxGcxyZH+PY5aCS7O/XElzSSkR1jFZ2s3/MX7PVKgCahGK7+yWjPsiK2 R5oXebdObshUa8LHDE/3WgBUmTchkvKRTXV9cvGqzxEPhC2zrxArvwP5v6B4mhCn Vqo3Pv0Cyr+n65Z5Dzqz/9+m999LJjFTsTrug0p5b/qBJQKu2rQONe4lpZ0NFwwY ExyjdxILj7mqrQpKcA6V5Bel5ZCnlVsGfTshFL6Iux54VFlJyRMzKWZ+Gdv4av5k dbjz+re+CojKabn3ML/7pAQujK6Rqe58vPuHV78zkvAGJnQgJOOTrmYNYtn3oBqe ogdCN+/PREb/9U7i6mQv5hhdHs4tT9ROXaT9jyb8XSHXW+t9lBM= =g+Ad -----END PGP SIGNATURE----- Merge tag 'drm-next-2024-07-18' of https://gitlab.freedesktop.org/drm/kernel Pull drm updates from Dave Airlie: "There's a lot of stuff in here, amd, i915 and xe have new platform work, lots of core rework around EDID handling, some new COMPILE_TEST options, maintainer changes and a lots of other stuff. Summary: core: - deprecate DRM data and return 0 date - connector: Create a set of helpers to help with HDMI support - Remove driver owner assignments - Allow more drivers to compile with COMPILE_TEST - Conversions to drm_edid - Sprinkle MODULE_DESCRIPTIONS everywhere they are missing - Remove drm_mm_replace_node - print: Add a drm prefix to warn level messages too, remove ___drm_dbg, consolidate prefix handling - New monochrome TV mode variant ttm: - improve number of page faults on some platforms - fix test builds under PREEMPT_RT - more test coverage ci: - Require a more recent version of mesa - improve farm setup and test generation dma-buf: - warn if reserving 0 fence slots - internal API heap enhancements fbdev: - Create memory manager optimized fbdev emulation panic: - Allow to select fonts - improve drm_fb_dma_get_scanout_buffer - Allow to dump kmsg to the screen bridge: - Remove redundant checks on bridge->encoder - Remove drm_bridge_chain_mode_fixup - bridge-connector: Plumb in the new HDMI helper - analogix_dp: Various improvements, handle AUX transfers timeout - samsung-dsim: Fix timings calculation - tc358767: Plenty of small fixes, fix no connector attach, fix clocks - sii902x: state validation improvements panels: - Switch panels from register table initialization to proper code - Now that the panel code tracks the panel state, remove every ad-hoc implementation in the panel drivers - More cleanup of prepare / enable state tracking in drivers - edp: Drop legacy panel compatibles - simple-bridge: Switch to devm_drm_bridge_add - New panels: Lincoln Tech Sol LCD185-101CT, Microtips Technology 13-101HIEBCAF0-C, Microtips Technology MF-103HIEB0GA0, BOE nv110wum-l60, IVO t109nw41, WL-355608-A8, PrimeView PM070WL4, Lincoln Technologies LCD197, Ortustech COM35H3P70ULC, AUO G104STN01, K&d kd101ne3-40ti amdgpu: - DCN 4.0.x support - GC 12.0 support - GMC 12.0 support - SDMA 7.0 support - MES12 support - MMHUB 4.1 support - GFX12 modifier and DCC support - lots of IP fixes/updates amdkfd: - Contiguous VRAM allocations - GC 12.0 support - SDMA 7.0 support - SR-IOV fixes - KFD GFX ALU exceptions i915: - Battlemage Xe2 HPD display enablement - Panel Replay enabling - DP AUX-less ALPM/LOBF - Enable link training failure fallback for DP MST links - CMRR (Content Match Refresh Rate) enabling - Increase ADL-S/ADL-P/DG2+ max TMDS bitrate to 6 Gbps - Enable eDP AUX based HDR backlight - Support replaying GPU hangs with captured context image - Automate CCS Mode setting during engine resets - lots of refactoring - Support replaying GPU hangs with captured context image - Increase FLR timeout from 3s to 9s - Enable w/a 16021333562 for DG2, MTL and ARL [guc] xe: - update MAINATINERS - New uapi adding OA functionality to Xe - expose l3 bank mask - fix display detect on ADL-N - runtime PM Fixes - Fix silent backmerge issues - More prep for SR-IOV - HWmon additions - per client usage info - Rework GPU page fault handling - Drop EXEC_QUEUE_FLAG_BANNED - Add BMG PCI IDs - Scheduler fixes and improvements - Rename xe_exec_queue::compute to xe_exec_queue::lr - Use ttm_uncached for BO with NEEDS_UC flag - Rename xe perf layer as xe observation layer - lots of refactoring radeon: - Backlight workaround for iMac - Silence UBSAN flex array warnings msm: - Validate registers XML description against schema in CI - core/dpu: SM7150 support - mdp5: Add support for MSM8937 - gpu: Add param for userspace to know if raytracing is supported - gpu: X185 support (aka gpu in X1 laptop chips) - gpu: a505 support ivpu: - hardware scheduler support - profiling support - improvements to the platform support layer - firmware handling improvements - clocks/power mgmt improvements - scheduler/logging improvements habanalabs: - Gradual sleep in polling memory macro - Reduce Gaudi2 MSI-X interrupt count to 128 - Add Gaudi2-D revision support - Add timestamp to CPLD info - Gaudi2: Assume hard-reset by firmware upon MC SEI severe error - Align Gaudi2 interrupt names - Check for errors after preboot is ready - Change habanalabs maintainer and git repo path mgag200: - refactoring and improvements - Add BMC output - enable polling nouveau: - add registry command line v3d: - perf counters improvements zynqmp: - irq and debugfs improvements atmel-hlcdc: - Support XLCDC in sam9x7 mipi-dbi: - Remove mipi_dbi_machine_little_endian - make SPI bits per word configurable - support RGB888 - allow pixel formats to be specified in the DT sun4i: - Rework the blender setup for DE2 panfrost: - Enable MT8188 support vc4: - Monochrome TV support exynos: - fix fallback mode regression - fix memory leak - Use drm_edid_duplicate() instead of kmemdup() etnaviv: - fix i.MX8MP NPU clock gating - workaround FE register cdc issues on some cores - fix DMA sync handling for cached buffers - fix job timeout handling - keep TS enabled on MMUv2 cores for improved performance mediatek: - Convert to platform remove callback returning void- - Drop chain_mode_fixup call in mode_valid() - Fixes the errors of MediaTek display driver found by IGT - Add display support for the MT8365-EVK board - Fix bit depth overwritten for mtk_ovl_set bit_depth() - Fix possible_crtcs calculation - Fix spurious kfree() ast: - refactor mode setting code stm: - Add LVDS support - DSI PHY updates" * tag 'drm-next-2024-07-18' of https://gitlab.freedesktop.org/drm/kernel: (2501 commits) drm/amdgpu/mes12: add missing opcode string drm/amdgpu/mes11: update opcode strings Revert "drm/amd/display: Reset freesync config before update new state" drm/omap: Restrict compile testing to PAGE_SIZE less than 64KB drm/xe: Drop trace_xe_hw_fence_free drm/xe/uapi: Rename xe perf layer as xe observation layer drm/amdgpu: remove exp hw support check for gfx12 drm/amdgpu: timely save bad pages to eeprom after gpu ras reset is completed drm/amdgpu: flush all cached ras bad pages to eeprom drm/amdgpu: select compute ME engines dynamically drm/amd/display: Allow display DCC for DCN401 drm/amdgpu: select compute ME engines dynamically drm/amdgpu/job: Replace DRM_INFO/ERROR logging drm/amdgpu: select compute ME engines dynamically drm/amd/pm: Ignore initial value in smu response register drm/amdgpu: Initialize VF partition mode drm/amd/amdgpu: fix SDMA IRQ client ID <-> req mapping MAINTAINERS: fix Xinhui's name MAINTAINERS: update powerplay and swsmu drm/qxl: Pin buffer objects for internal mappings ...
351 lines
9.2 KiB
C
351 lines
9.2 KiB
C
// SPDX-License-Identifier: MIT
|
|
|
|
#include <linux/moduleparam.h>
|
|
#include <linux/vmalloc.h>
|
|
|
|
#include <drm/drm_crtc_helper.h>
|
|
#include <drm/drm_drv.h>
|
|
#include <drm/drm_fb_helper.h>
|
|
#include <drm/drm_framebuffer.h>
|
|
#include <drm/drm_gem.h>
|
|
#include <drm/drm_print.h>
|
|
|
|
#include <drm/drm_fbdev_ttm.h>
|
|
|
|
/* @user: 1=userspace, 0=fbcon */
|
|
static int drm_fbdev_ttm_fb_open(struct fb_info *info, int user)
|
|
{
|
|
struct drm_fb_helper *fb_helper = info->par;
|
|
|
|
/* No need to take a ref for fbcon because it unbinds on unregister */
|
|
if (user && !try_module_get(fb_helper->dev->driver->fops->owner))
|
|
return -ENODEV;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int drm_fbdev_ttm_fb_release(struct fb_info *info, int user)
|
|
{
|
|
struct drm_fb_helper *fb_helper = info->par;
|
|
|
|
if (user)
|
|
module_put(fb_helper->dev->driver->fops->owner);
|
|
|
|
return 0;
|
|
}
|
|
|
|
FB_GEN_DEFAULT_DEFERRED_SYSMEM_OPS(drm_fbdev_ttm,
|
|
drm_fb_helper_damage_range,
|
|
drm_fb_helper_damage_area);
|
|
|
|
static void drm_fbdev_ttm_fb_destroy(struct fb_info *info)
|
|
{
|
|
struct drm_fb_helper *fb_helper = info->par;
|
|
void *shadow = info->screen_buffer;
|
|
|
|
if (!fb_helper->dev)
|
|
return;
|
|
|
|
fb_deferred_io_cleanup(info);
|
|
drm_fb_helper_fini(fb_helper);
|
|
vfree(shadow);
|
|
drm_client_framebuffer_delete(fb_helper->buffer);
|
|
|
|
drm_client_release(&fb_helper->client);
|
|
drm_fb_helper_unprepare(fb_helper);
|
|
kfree(fb_helper);
|
|
}
|
|
|
|
static const struct fb_ops drm_fbdev_ttm_fb_ops = {
|
|
.owner = THIS_MODULE,
|
|
.fb_open = drm_fbdev_ttm_fb_open,
|
|
.fb_release = drm_fbdev_ttm_fb_release,
|
|
FB_DEFAULT_DEFERRED_OPS(drm_fbdev_ttm),
|
|
DRM_FB_HELPER_DEFAULT_OPS,
|
|
.fb_destroy = drm_fbdev_ttm_fb_destroy,
|
|
};
|
|
|
|
/*
|
|
* This function uses the client API to create a framebuffer backed by a dumb buffer.
|
|
*/
|
|
static int drm_fbdev_ttm_helper_fb_probe(struct drm_fb_helper *fb_helper,
|
|
struct drm_fb_helper_surface_size *sizes)
|
|
{
|
|
struct drm_client_dev *client = &fb_helper->client;
|
|
struct drm_device *dev = fb_helper->dev;
|
|
struct drm_client_buffer *buffer;
|
|
struct fb_info *info;
|
|
size_t screen_size;
|
|
void *screen_buffer;
|
|
u32 format;
|
|
int ret;
|
|
|
|
drm_dbg_kms(dev, "surface width(%d), height(%d) and bpp(%d)\n",
|
|
sizes->surface_width, sizes->surface_height,
|
|
sizes->surface_bpp);
|
|
|
|
format = drm_driver_legacy_fb_format(dev, sizes->surface_bpp,
|
|
sizes->surface_depth);
|
|
buffer = drm_client_framebuffer_create(client, sizes->surface_width,
|
|
sizes->surface_height, format);
|
|
if (IS_ERR(buffer))
|
|
return PTR_ERR(buffer);
|
|
|
|
fb_helper->buffer = buffer;
|
|
fb_helper->fb = buffer->fb;
|
|
|
|
screen_size = buffer->gem->size;
|
|
screen_buffer = vzalloc(screen_size);
|
|
if (!screen_buffer) {
|
|
ret = -ENOMEM;
|
|
goto err_drm_client_framebuffer_delete;
|
|
}
|
|
|
|
info = drm_fb_helper_alloc_info(fb_helper);
|
|
if (IS_ERR(info)) {
|
|
ret = PTR_ERR(info);
|
|
goto err_vfree;
|
|
}
|
|
|
|
drm_fb_helper_fill_info(info, fb_helper, sizes);
|
|
|
|
info->fbops = &drm_fbdev_ttm_fb_ops;
|
|
|
|
/* screen */
|
|
info->flags |= FBINFO_VIRTFB | FBINFO_READS_FAST;
|
|
info->screen_buffer = screen_buffer;
|
|
info->fix.smem_len = screen_size;
|
|
|
|
/* deferred I/O */
|
|
fb_helper->fbdefio.delay = HZ / 20;
|
|
fb_helper->fbdefio.deferred_io = drm_fb_helper_deferred_io;
|
|
|
|
info->fbdefio = &fb_helper->fbdefio;
|
|
ret = fb_deferred_io_init(info);
|
|
if (ret)
|
|
goto err_drm_fb_helper_release_info;
|
|
|
|
return 0;
|
|
|
|
err_drm_fb_helper_release_info:
|
|
drm_fb_helper_release_info(fb_helper);
|
|
err_vfree:
|
|
vfree(screen_buffer);
|
|
err_drm_client_framebuffer_delete:
|
|
fb_helper->fb = NULL;
|
|
fb_helper->buffer = NULL;
|
|
drm_client_framebuffer_delete(buffer);
|
|
return ret;
|
|
}
|
|
|
|
static void drm_fbdev_ttm_damage_blit_real(struct drm_fb_helper *fb_helper,
|
|
struct drm_clip_rect *clip,
|
|
struct iosys_map *dst)
|
|
{
|
|
struct drm_framebuffer *fb = fb_helper->fb;
|
|
size_t offset = clip->y1 * fb->pitches[0];
|
|
size_t len = clip->x2 - clip->x1;
|
|
unsigned int y;
|
|
void *src;
|
|
|
|
switch (drm_format_info_bpp(fb->format, 0)) {
|
|
case 1:
|
|
offset += clip->x1 / 8;
|
|
len = DIV_ROUND_UP(len + clip->x1 % 8, 8);
|
|
break;
|
|
case 2:
|
|
offset += clip->x1 / 4;
|
|
len = DIV_ROUND_UP(len + clip->x1 % 4, 4);
|
|
break;
|
|
case 4:
|
|
offset += clip->x1 / 2;
|
|
len = DIV_ROUND_UP(len + clip->x1 % 2, 2);
|
|
break;
|
|
default:
|
|
offset += clip->x1 * fb->format->cpp[0];
|
|
len *= fb->format->cpp[0];
|
|
break;
|
|
}
|
|
|
|
src = fb_helper->info->screen_buffer + offset;
|
|
iosys_map_incr(dst, offset); /* go to first pixel within clip rect */
|
|
|
|
for (y = clip->y1; y < clip->y2; y++) {
|
|
iosys_map_memcpy_to(dst, 0, src, len);
|
|
iosys_map_incr(dst, fb->pitches[0]);
|
|
src += fb->pitches[0];
|
|
}
|
|
}
|
|
|
|
static int drm_fbdev_ttm_damage_blit(struct drm_fb_helper *fb_helper,
|
|
struct drm_clip_rect *clip)
|
|
{
|
|
struct drm_client_buffer *buffer = fb_helper->buffer;
|
|
struct iosys_map map, dst;
|
|
int ret;
|
|
|
|
/*
|
|
* We have to pin the client buffer to its current location while
|
|
* flushing the shadow buffer. In the general case, concurrent
|
|
* modesetting operations could try to move the buffer and would
|
|
* fail. The modeset has to be serialized by acquiring the reservation
|
|
* object of the underlying BO here.
|
|
*
|
|
* For fbdev emulation, we only have to protect against fbdev modeset
|
|
* operations. Nothing else will involve the client buffer's BO. So it
|
|
* is sufficient to acquire struct drm_fb_helper.lock here.
|
|
*/
|
|
mutex_lock(&fb_helper->lock);
|
|
|
|
ret = drm_client_buffer_vmap_local(buffer, &map);
|
|
if (ret)
|
|
goto out;
|
|
|
|
dst = map;
|
|
drm_fbdev_ttm_damage_blit_real(fb_helper, clip, &dst);
|
|
|
|
drm_client_buffer_vunmap_local(buffer);
|
|
|
|
out:
|
|
mutex_unlock(&fb_helper->lock);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int drm_fbdev_ttm_helper_fb_dirty(struct drm_fb_helper *helper,
|
|
struct drm_clip_rect *clip)
|
|
{
|
|
struct drm_device *dev = helper->dev;
|
|
int ret;
|
|
|
|
/* Call damage handlers only if necessary */
|
|
if (!(clip->x1 < clip->x2 && clip->y1 < clip->y2))
|
|
return 0;
|
|
|
|
ret = drm_fbdev_ttm_damage_blit(helper, clip);
|
|
if (drm_WARN_ONCE(dev, ret, "Damage blitter failed: ret=%d\n", ret))
|
|
return ret;
|
|
|
|
if (helper->fb->funcs->dirty) {
|
|
ret = helper->fb->funcs->dirty(helper->fb, NULL, 0, 0, clip, 1);
|
|
if (drm_WARN_ONCE(dev, ret, "Dirty helper failed: ret=%d\n", ret))
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct drm_fb_helper_funcs drm_fbdev_ttm_helper_funcs = {
|
|
.fb_probe = drm_fbdev_ttm_helper_fb_probe,
|
|
.fb_dirty = drm_fbdev_ttm_helper_fb_dirty,
|
|
};
|
|
|
|
static void drm_fbdev_ttm_client_unregister(struct drm_client_dev *client)
|
|
{
|
|
struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
|
|
|
|
if (fb_helper->info) {
|
|
drm_fb_helper_unregister_info(fb_helper);
|
|
} else {
|
|
drm_client_release(&fb_helper->client);
|
|
drm_fb_helper_unprepare(fb_helper);
|
|
kfree(fb_helper);
|
|
}
|
|
}
|
|
|
|
static int drm_fbdev_ttm_client_restore(struct drm_client_dev *client)
|
|
{
|
|
drm_fb_helper_lastclose(client->dev);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int drm_fbdev_ttm_client_hotplug(struct drm_client_dev *client)
|
|
{
|
|
struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
|
|
struct drm_device *dev = client->dev;
|
|
int ret;
|
|
|
|
if (dev->fb_helper)
|
|
return drm_fb_helper_hotplug_event(dev->fb_helper);
|
|
|
|
ret = drm_fb_helper_init(dev, fb_helper);
|
|
if (ret)
|
|
goto err_drm_err;
|
|
|
|
if (!drm_drv_uses_atomic_modeset(dev))
|
|
drm_helper_disable_unused_functions(dev);
|
|
|
|
ret = drm_fb_helper_initial_config(fb_helper);
|
|
if (ret)
|
|
goto err_drm_fb_helper_fini;
|
|
|
|
return 0;
|
|
|
|
err_drm_fb_helper_fini:
|
|
drm_fb_helper_fini(fb_helper);
|
|
err_drm_err:
|
|
drm_err(dev, "fbdev: Failed to setup emulation (ret=%d)\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
static const struct drm_client_funcs drm_fbdev_ttm_client_funcs = {
|
|
.owner = THIS_MODULE,
|
|
.unregister = drm_fbdev_ttm_client_unregister,
|
|
.restore = drm_fbdev_ttm_client_restore,
|
|
.hotplug = drm_fbdev_ttm_client_hotplug,
|
|
};
|
|
|
|
/**
|
|
* drm_fbdev_ttm_setup() - Setup fbdev emulation for TTM-based drivers
|
|
* @dev: DRM device
|
|
* @preferred_bpp: Preferred bits per pixel for the device.
|
|
*
|
|
* This function sets up fbdev emulation for TTM-based drivers that support
|
|
* dumb buffers with a virtual address and that can be mmap'ed.
|
|
* drm_fbdev_ttm_setup() shall be called after the DRM driver registered
|
|
* the new DRM device with drm_dev_register().
|
|
*
|
|
* Restore, hotplug events and teardown are all taken care of. Drivers that do
|
|
* suspend/resume need to call drm_fb_helper_set_suspend_unlocked() themselves.
|
|
* Simple drivers might use drm_mode_config_helper_suspend().
|
|
*
|
|
* In order to provide fixed mmap-able memory ranges, fbdev emulation
|
|
* uses a shadow buffer in system memory. The implementation blits the shadow
|
|
* fbdev buffer onto the real buffer in regular intervals.
|
|
*
|
|
* This function is safe to call even when there are no connectors present.
|
|
* Setup will be retried on the next hotplug event.
|
|
*
|
|
* The fbdev is destroyed by drm_dev_unregister().
|
|
*/
|
|
void drm_fbdev_ttm_setup(struct drm_device *dev, unsigned int preferred_bpp)
|
|
{
|
|
struct drm_fb_helper *fb_helper;
|
|
int ret;
|
|
|
|
drm_WARN(dev, !dev->registered, "Device has not been registered.\n");
|
|
drm_WARN(dev, dev->fb_helper, "fb_helper is already set!\n");
|
|
|
|
fb_helper = kzalloc(sizeof(*fb_helper), GFP_KERNEL);
|
|
if (!fb_helper)
|
|
return;
|
|
drm_fb_helper_prepare(dev, fb_helper, preferred_bpp, &drm_fbdev_ttm_helper_funcs);
|
|
|
|
ret = drm_client_init(dev, &fb_helper->client, "fbdev", &drm_fbdev_ttm_client_funcs);
|
|
if (ret) {
|
|
drm_err(dev, "Failed to register client: %d\n", ret);
|
|
goto err_drm_client_init;
|
|
}
|
|
|
|
drm_client_register(&fb_helper->client);
|
|
|
|
return;
|
|
|
|
err_drm_client_init:
|
|
drm_fb_helper_unprepare(fb_helper);
|
|
kfree(fb_helper);
|
|
return;
|
|
}
|
|
EXPORT_SYMBOL(drm_fbdev_ttm_setup);
|