File Index
Files and directories
Sign in
FILE

drm_fbdev_client.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/clients/drm_fbdev_client.c C
  1// SPDX-License-Identifier: MIT
  2
  3#include <drm/drm_client.h>
  4#include <drm/drm_crtc_helper.h>
  5#include <drm/drm_drv.h>
  6#include <drm/drm_fb_helper.h>
  7#include <drm/drm_fourcc.h>
  8#include <drm/drm_print.h>
  9
 10#include "drm_client_internal.h"
 11
 12/*
 13 * struct drm_client_funcs
 14 */
 15
 16static void drm_fbdev_client_free(struct drm_client_dev *client)
 17{
 18	struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
 19
 20	drm_fb_helper_unprepare(fb_helper);
 21	kfree(fb_helper);
 22}
 23
 24static void drm_fbdev_client_unregister(struct drm_client_dev *client)
 25{
 26	struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
 27
 28	if (fb_helper->info) {
 29		/*
 30		 * Fully probed framebuffer device
 31		 */
 32		drm_fb_helper_unregister_info(fb_helper);
 33	} else {
 34		/*
 35		 * Partially initialized client, no framebuffer device yet
 36		 */
 37		drm_client_release(&fb_helper->client);
 38	}
 39}
 40
 41static int drm_fbdev_client_restore(struct drm_client_dev *client, bool force)
 42{
 43	struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
 44
 45	drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper, force);
 46
 47	return 0;
 48}
 49
 50static int drm_fbdev_client_hotplug(struct drm_client_dev *client)
 51{
 52	struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
 53	struct drm_device *dev = client->dev;
 54	int ret;
 55
 56	if (dev->fb_helper)
 57		return drm_fb_helper_hotplug_event(dev->fb_helper);
 58
 59	ret = drm_fb_helper_init(dev, fb_helper);
 60	if (ret)
 61		goto err_drm_err;
 62
 63	if (!drm_drv_uses_atomic_modeset(dev))
 64		drm_helper_disable_unused_functions(dev);
 65
 66	ret = drm_fb_helper_initial_config(fb_helper);
 67	if (ret)
 68		goto err_drm_fb_helper_fini;
 69
 70	return 0;
 71
 72err_drm_fb_helper_fini:
 73	drm_fb_helper_fini(fb_helper);
 74err_drm_err:
 75	drm_err(dev, "fbdev: Failed to setup emulation (ret=%d)\n", ret);
 76	return ret;
 77}
 78
 79static int drm_fbdev_client_suspend(struct drm_client_dev *client)
 80{
 81	struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
 82
 83	drm_fb_helper_set_suspend_unlocked(fb_helper, true);
 84
 85	return 0;
 86}
 87
 88static int drm_fbdev_client_resume(struct drm_client_dev *client)
 89{
 90	struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
 91
 92	drm_fb_helper_set_suspend_unlocked(fb_helper, false);
 93
 94	return 0;
 95}
 96
 97static const struct drm_client_funcs drm_fbdev_client_funcs = {
 98	.owner		= THIS_MODULE,
 99	.free		= drm_fbdev_client_free,
100	.unregister	= drm_fbdev_client_unregister,
101	.restore	= drm_fbdev_client_restore,
102	.hotplug	= drm_fbdev_client_hotplug,
103	.suspend	= drm_fbdev_client_suspend,
104	.resume		= drm_fbdev_client_resume,
105};
106
107/**
108 * drm_fbdev_client_setup() - Setup fbdev emulation
109 * @dev: DRM device
110 * @format: Preferred color format for the device. DRM_FORMAT_XRGB8888
111 *          is used if this is zero.
112 *
113 * This function sets up fbdev emulation. Restore, hotplug events and
114 * teardown are all taken care of. Drivers that do suspend/resume need
115 * to call drm_client_dev_suspend() and drm_client_dev_resume() by
116 * themselves. Simple drivers might use drm_mode_config_helper_suspend().
117 *
118 * This function is safe to call even when there are no connectors present.
119 * Setup will be retried on the next hotplug event.
120 *
121 * The fbdev client is destroyed by drm_dev_unregister().
122 *
123 * Returns:
124 * 0 on success, or a negative errno code otherwise.
125 */
126int drm_fbdev_client_setup(struct drm_device *dev, const struct drm_format_info *format)
127{
128	struct drm_fb_helper *fb_helper;
129	unsigned int color_mode;
130	int ret;
131
132	/* TODO: Use format info throughout DRM */
133	if (format) {
134		unsigned int bpp = drm_format_info_bpp(format, 0);
135
136		switch (bpp) {
137		case 16:
138			color_mode = format->depth; // could also be 15
139			break;
140		default:
141			color_mode = bpp;
142		}
143	} else {
144		switch (dev->mode_config.preferred_depth) {
145		case 0:
146		case 24:
147			color_mode = 32;
148			break;
149		default:
150			color_mode = dev->mode_config.preferred_depth;
151		}
152	}
153
154	drm_WARN(dev, !dev->registered, "Device has not been registered.\n");
155	drm_WARN(dev, dev->fb_helper, "fb_helper is already set!\n");
156
157	fb_helper = kzalloc(sizeof(*fb_helper), GFP_KERNEL);
158	if (!fb_helper)
159		return -ENOMEM;
160	drm_fb_helper_prepare(dev, fb_helper, color_mode, NULL);
161
162	ret = drm_client_init(dev, &fb_helper->client, "fbdev", &drm_fbdev_client_funcs);
163	if (ret) {
164		drm_err(dev, "Failed to register client: %d\n", ret);
165		goto err_drm_client_init;
166	}
167
168	drm_client_register(&fb_helper->client);
169
170	return 0;
171
172err_drm_client_init:
173	drm_fb_helper_unprepare(fb_helper);
174	kfree(fb_helper);
175	return ret;
176}
~/ Read-only file preview.