From 88b8ae7642ef21e685d51148e8f57c3dfa1323ac Mon Sep 17 00:00:00 2001 From: Bingwu Zhang Date: Sat, 7 Dec 2024 23:56:43 +0800 Subject: [PATCH 10/10] FROM AOSC: TTM fbdev emulation for Linux 6.13+ Link: https://github.com/torvalds/linux/commit/1000634477d8d178179b1ad45d92e925fabe3deb Link: https://github.com/NVIDIA/open-gpu-kernel-modules/issues/749 Signed-off-by: xtex Signed-off-by: Eric Naim --- kernel-open/nvidia-drm/nvidia-drm-drv.c | 72 +++++++++++++++++++ kernel-open/nvidia-drm/nvidia-drm-linux.c | 4 ++ .../nvidia-drm/nvidia-drm-os-interface.h | 5 ++ 3 files changed, 81 insertions(+) diff --git a/kernel-open/nvidia-drm/nvidia-drm-drv.c b/kernel-open/nvidia-drm/nvidia-drm-drv.c index 2e4f6404..ab85152f 100644 --- a/kernel-open/nvidia-drm/nvidia-drm-drv.c +++ b/kernel-open/nvidia-drm/nvidia-drm-drv.c @@ -1951,7 +1951,60 @@ void nv_drm_update_drm_driver_features(void) #endif /* NV_DRM_ATOMIC_MODESET_AVAILABLE */ } +#if !defined(NV_DRM_FBDEV_TTM_AVAILABLE) && \ + !defined(NV_DRM_FBDEV_GENERIC_AVAILABLE) +// AOSC OS: Workaround for Linux 6.13+ +static const struct drm_fb_helper_funcs nv_drm_fbdev_helper_funcs = { + .fb_probe = drm_fbdev_ttm_driver_fbdev_probe, +}; + +static void nv_drm_fbdev_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 nv_drm_fbdev_client_restore(struct drm_client_dev *client) +{ + drm_fb_helper_lastclose(client->dev); + return 0; +} +static int nv_drm_fbdev_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, "AOSC OS: NV-DRM: fbdev: Failed to setup emulation (ret=%d)\n", ret); + return ret; +} + +static const struct drm_client_funcs nv_drm_fbdev_client_funcs = { + .owner = THIS_MODULE, + .unregister = nv_drm_fbdev_client_unregister, + .restore = nv_drm_fbdev_client_restore, + .hotplug = nv_drm_fbdev_client_hotplug, +}; +#endif /* * Helper function for allocate/register DRM device for given NVIDIA GPU ID. @@ -1961,6 +2014,7 @@ void nv_drm_register_drm_device(const nv_gpu_info_t *gpu_info) struct nv_drm_device *nv_dev = NULL; struct drm_device *dev = NULL; struct device *device = gpu_info->os_device_ptr; + struct drm_fb_helper *fb_helper = NULL; bool bus_is_pci; DRM_DEBUG( @@ -2039,6 +2093,20 @@ void nv_drm_register_drm_device(const nv_gpu_info_t *gpu_info) drm_fbdev_ttm_setup(dev, 32); #elif defined(NV_DRM_FBDEV_GENERIC_AVAILABLE) drm_fbdev_generic_setup(dev, 32); + #else + // AOSC OS: Workaround for Linux 6.13+ + int drm_client_ret; + fb_helper = kzalloc(sizeof(*fb_helper), GFP_KERNEL); + if (!fb_helper) + return; + drm_fb_helper_prepare(dev, fb_helper, 32, &nv_drm_fbdev_helper_funcs); + drm_client_ret = drm_client_init(dev, &fb_helper->client, "fbdev", + &nv_drm_fbdev_client_funcs); + if (drm_client_ret) { + drm_err(dev, "AOSC OS: NV-DRM: Failed to register DRM client: %d\n", drm_client_ret); + goto failed_drm_client_init; + } + drm_client_register(&fb_helper->client); #endif } #endif /* defined(NV_DRM_FBDEV_AVAILABLE) */ @@ -2050,6 +2118,10 @@ void nv_drm_register_drm_device(const nv_gpu_info_t *gpu_info) return; /* Success */ +failed_drm_client_init: + drm_fb_helper_unprepare(fb_helper); + kfree(fb_helper); + failed_drm_register: nv_drm_dev_free(dev); diff --git a/kernel-open/nvidia-drm/nvidia-drm-linux.c b/kernel-open/nvidia-drm/nvidia-drm-linux.c index 83d40983..ac4fe967 100644 --- a/kernel-open/nvidia-drm/nvidia-drm-linux.c +++ b/kernel-open/nvidia-drm/nvidia-drm-linux.c @@ -39,8 +39,12 @@ MODULE_PARM_DESC( fbdev, "Create a framebuffer device (1 = enable (default), 0 = disable) (EXPERIMENTAL)"); module_param_named(fbdev, nv_drm_fbdev_module_param, bool, 0400); +#else +#error "nvidia-drm fbdev should always be available." #endif +#else +#error "nvidia-drm is not available" #endif /* NV_DRM_AVAILABLE */ /************************************************************************* diff --git a/kernel-open/nvidia-drm/nvidia-drm-os-interface.h b/kernel-open/nvidia-drm/nvidia-drm-os-interface.h index 71ca5f22..8195af32 100644 --- a/kernel-open/nvidia-drm/nvidia-drm-os-interface.h +++ b/kernel-open/nvidia-drm/nvidia-drm-os-interface.h @@ -78,6 +78,11 @@ typedef struct nv_timer nv_drm_timer; #define NV_DRM_FBDEV_TTM_AVAILABLE #endif +// AOSC OS: Always enable DRM fbdev +// FIXME: Add config test for drm helper functions. +// The implementation uses drm_client_register, which is added in v5.2-rc1. +#define NV_DRM_FBDEV_AVAILABLE + struct page; /* Set to true when the atomic modeset feature is enabled. */ -- 2.47.1