Skip to content

Commit 49953b7

Browse files
Thomas Zimmermanndaeinki
authored andcommitted
drm/exynos: Implement fbdev emulation as in-kernel client
Move code from ad-hoc fbdev callbacks into DRM client functions and remove the old callbacks. The functions instruct the client to poll for changed output or restore the display. The DRM core calls both, the old callbacks and the new client helpers, from the same places. The new functions perform the same operation as before, so there's no change in functionality. Replace all code that initializes or releases fbdev emulation throughout the driver. Instead initialize the fbdev client by a single call to exynos_fbdev_setup() after exynos has registered its DRM device. As in most drivers, exynos' fbdev emulation now acts like a regular DRM client. The fbdev client setup consists of the initial preparation and the hot-plugging of the display. The latter creates the fbdev device and sets up the fbdev framebuffer. The setup performs display hot-plugging once. If no display can be detected, DRM probe helpers re-run the detection on each hotplug event. A call to drm_dev_unregister() releases the client automatically. No further action is required within exynos. If the fbdev framebuffer has been fully set up, struct fb_ops.fb_destroy implements the release. For partially initialized emulation, the fbdev client reverts the initial setup. Signed-off-by: Thomas Zimmermann <[email protected]> Tested-by: Marek Szyprowski <[email protected]> Signed-off-by: Inki Dae <[email protected]>
1 parent 9928648 commit 49953b7

File tree

4 files changed

+77
-108
lines changed

4 files changed

+77
-108
lines changed

drivers/gpu/drm/exynos/exynos_drm_drv.c

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
#include <drm/drm_atomic.h>
1717
#include <drm/drm_atomic_helper.h>
1818
#include <drm/drm_drv.h>
19-
#include <drm/drm_fb_helper.h>
2019
#include <drm/drm_file.h>
2120
#include <drm/drm_fourcc.h>
2221
#include <drm/drm_ioctl.h>
@@ -108,7 +107,6 @@ static const struct drm_driver exynos_drm_driver = {
108107
.driver_features = DRIVER_MODESET | DRIVER_GEM
109108
| DRIVER_ATOMIC | DRIVER_RENDER,
110109
.open = exynos_drm_open,
111-
.lastclose = drm_fb_helper_lastclose,
112110
.postclose = exynos_drm_postclose,
113111
.dumb_create = exynos_drm_gem_dumb_create,
114112
.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
@@ -288,19 +286,15 @@ static int exynos_drm_bind(struct device *dev)
288286
/* init kms poll for handling hpd */
289287
drm_kms_helper_poll_init(drm);
290288

291-
ret = exynos_drm_fbdev_init(drm);
292-
if (ret)
293-
goto err_cleanup_poll;
294-
295289
/* register the DRM device */
296290
ret = drm_dev_register(drm, 0);
297291
if (ret < 0)
298-
goto err_cleanup_fbdev;
292+
goto err_cleanup_poll;
293+
294+
exynos_drm_fbdev_setup(drm);
299295

300296
return 0;
301297

302-
err_cleanup_fbdev:
303-
exynos_drm_fbdev_fini(drm);
304298
err_cleanup_poll:
305299
drm_kms_helper_poll_fini(drm);
306300
err_unbind_all:
@@ -321,7 +315,6 @@ static void exynos_drm_unbind(struct device *dev)
321315

322316
drm_dev_unregister(drm);
323317

324-
exynos_drm_fbdev_fini(drm);
325318
drm_kms_helper_poll_fini(drm);
326319

327320
component_unbind_all(drm->dev, drm);

drivers/gpu/drm/exynos/exynos_drm_fb.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
#include <drm/drm_atomic.h>
1212
#include <drm/drm_atomic_helper.h>
1313
#include <drm/drm_crtc.h>
14-
#include <drm/drm_fb_helper.h>
1514
#include <drm/drm_framebuffer.h>
1615
#include <drm/drm_fourcc.h>
1716
#include <drm/drm_gem_framebuffer_helper.h>
@@ -157,7 +156,6 @@ static struct drm_mode_config_helper_funcs exynos_drm_mode_config_helpers = {
157156

158157
static const struct drm_mode_config_funcs exynos_drm_mode_config_funcs = {
159158
.fb_create = exynos_user_fb_create,
160-
.output_poll_changed = drm_fb_helper_output_poll_changed,
161159
.atomic_check = drm_atomic_helper_check,
162160
.atomic_commit = drm_atomic_helper_commit,
163161
};

drivers/gpu/drm/exynos/exynos_drm_fbdev.c

Lines changed: 72 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,12 @@
88
* Seung-Woo Kim <[email protected]>
99
*/
1010

11-
#include <linux/console.h>
12-
#include <linux/dma-mapping.h>
13-
#include <linux/vmalloc.h>
14-
15-
#include <drm/drm_crtc.h>
11+
#include <drm/drm_crtc_helper.h>
12+
#include <drm/drm_drv.h>
1613
#include <drm/drm_fb_helper.h>
17-
#include <drm/drm_fourcc.h>
1814
#include <drm/drm_framebuffer.h>
1915
#include <drm/drm_gem_framebuffer_helper.h>
2016
#include <drm/drm_prime.h>
21-
#include <drm/drm_probe_helper.h>
2217
#include <drm/exynos_drm.h>
2318

2419
#include "exynos_drm_drv.h"
@@ -36,6 +31,20 @@ static int exynos_drm_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
3631
return drm_gem_prime_mmap(obj, vma);
3732
}
3833

34+
static void exynos_drm_fb_destroy(struct fb_info *info)
35+
{
36+
struct drm_fb_helper *fb_helper = info->par;
37+
struct drm_framebuffer *fb = fb_helper->fb;
38+
39+
drm_fb_helper_fini(fb_helper);
40+
41+
drm_framebuffer_remove(fb);
42+
43+
drm_client_release(&fb_helper->client);
44+
drm_fb_helper_unprepare(fb_helper);
45+
kfree(fb_helper);
46+
}
47+
3948
static const struct fb_ops exynos_drm_fb_ops = {
4049
.owner = THIS_MODULE,
4150
DRM_FB_HELPER_DEFAULT_OPS,
@@ -45,6 +54,7 @@ static const struct fb_ops exynos_drm_fb_ops = {
4554
.fb_fillrect = drm_fb_helper_cfb_fillrect,
4655
.fb_copyarea = drm_fb_helper_cfb_copyarea,
4756
.fb_imageblit = drm_fb_helper_cfb_imageblit,
57+
.fb_destroy = exynos_drm_fb_destroy,
4858
};
4959

5060
static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
@@ -115,19 +125,13 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,
115125
if (ret < 0)
116126
goto err_destroy_framebuffer;
117127

118-
return ret;
128+
return 0;
119129

120130
err_destroy_framebuffer:
121131
drm_framebuffer_cleanup(helper->fb);
132+
helper->fb = NULL;
122133
err_destroy_gem:
123134
exynos_drm_gem_destroy(exynos_gem);
124-
125-
/*
126-
* if failed, all resources allocated above would be released by
127-
* drm_mode_config_cleanup() when drm_load() had been called prior
128-
* to any specific driver such as fimd or hdmi driver.
129-
*/
130-
131135
return ret;
132136
}
133137

@@ -140,16 +144,52 @@ static const struct drm_fb_helper_funcs exynos_drm_fb_helper_funcs = {
140144
*/
141145

142146
static void exynos_drm_fbdev_client_unregister(struct drm_client_dev *client)
143-
{ }
147+
{
148+
struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
149+
150+
if (fb_helper->info) {
151+
drm_fb_helper_unregister_info(fb_helper);
152+
} else {
153+
drm_client_release(&fb_helper->client);
154+
drm_fb_helper_unprepare(fb_helper);
155+
kfree(fb_helper);
156+
}
157+
}
144158

145159
static int exynos_drm_fbdev_client_restore(struct drm_client_dev *client)
146160
{
161+
drm_fb_helper_lastclose(client->dev);
162+
147163
return 0;
148164
}
149165

150166
static int exynos_drm_fbdev_client_hotplug(struct drm_client_dev *client)
151167
{
168+
struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
169+
struct drm_device *dev = client->dev;
170+
int ret;
171+
172+
if (dev->fb_helper)
173+
return drm_fb_helper_hotplug_event(dev->fb_helper);
174+
175+
ret = drm_fb_helper_init(dev, fb_helper);
176+
if (ret)
177+
goto err_drm_err;
178+
179+
if (!drm_drv_uses_atomic_modeset(dev))
180+
drm_helper_disable_unused_functions(dev);
181+
182+
ret = drm_fb_helper_initial_config(fb_helper);
183+
if (ret)
184+
goto err_drm_fb_helper_fini;
185+
152186
return 0;
187+
188+
err_drm_fb_helper_fini:
189+
drm_fb_helper_fini(fb_helper);
190+
err_drm_err:
191+
drm_err(dev, "Failed to setup fbdev emulation (ret=%d)\n", ret);
192+
return ret;
153193
}
154194

155195
static const struct drm_client_funcs exynos_drm_fbdev_client_funcs = {
@@ -159,78 +199,32 @@ static const struct drm_client_funcs exynos_drm_fbdev_client_funcs = {
159199
.hotplug = exynos_drm_fbdev_client_hotplug,
160200
};
161201

162-
int exynos_drm_fbdev_init(struct drm_device *dev)
202+
void exynos_drm_fbdev_setup(struct drm_device *dev)
163203
{
164-
struct drm_fb_helper *helper;
204+
struct drm_fb_helper *fb_helper;
165205
int ret;
166206

167-
if (!dev->mode_config.num_crtc)
168-
return 0;
207+
drm_WARN(dev, !dev->registered, "Device has not been registered.\n");
208+
drm_WARN(dev, dev->fb_helper, "fb_helper is already set!\n");
169209

170-
helper = kzalloc(sizeof(*helper), GFP_KERNEL);
171-
if (!helper)
172-
return -ENOMEM;
173-
174-
drm_fb_helper_prepare(dev, helper, PREFERRED_BPP, &exynos_drm_fb_helper_funcs);
210+
fb_helper = kzalloc(sizeof(*fb_helper), GFP_KERNEL);
211+
if (!fb_helper)
212+
return;
213+
drm_fb_helper_prepare(dev, fb_helper, PREFERRED_BPP, &exynos_drm_fb_helper_funcs);
175214

176-
ret = drm_client_init(dev, &helper->client, "exynos-fbdev", &exynos_drm_fbdev_client_funcs);
215+
ret = drm_client_init(dev, &fb_helper->client, "fbdev", &exynos_drm_fbdev_client_funcs);
177216
if (ret)
178-
goto err_drm_fb_helper_unprepare;
179-
180-
ret = drm_fb_helper_init(dev, helper);
181-
if (ret < 0) {
182-
DRM_DEV_ERROR(dev->dev,
183-
"failed to initialize drm fb helper.\n");
184-
goto err_drm_client_release;
185-
}
186-
187-
ret = drm_fb_helper_initial_config(helper);
188-
if (ret < 0) {
189-
DRM_DEV_ERROR(dev->dev,
190-
"failed to set up hw configuration.\n");
191-
goto err_setup;
192-
}
193-
194-
return 0;
195-
196-
err_setup:
197-
drm_fb_helper_fini(helper);
198-
err_drm_client_release:
199-
drm_client_release(&helper->client);
200-
err_drm_fb_helper_unprepare:
201-
drm_fb_helper_unprepare(helper);
202-
kfree(helper);
203-
204-
return ret;
205-
}
206-
207-
static void exynos_drm_fbdev_destroy(struct drm_device *dev,
208-
struct drm_fb_helper *fb_helper)
209-
{
210-
struct drm_framebuffer *fb;
217+
goto err_drm_client_init;
211218

212-
/* release drm framebuffer and real buffer */
213-
if (fb_helper->fb && fb_helper->fb->funcs) {
214-
fb = fb_helper->fb;
215-
if (fb)
216-
drm_framebuffer_remove(fb);
217-
}
218-
219-
drm_fb_helper_unregister_info(fb_helper);
220-
221-
drm_fb_helper_fini(fb_helper);
222-
}
219+
ret = exynos_drm_fbdev_client_hotplug(&fb_helper->client);
220+
if (ret)
221+
drm_dbg_kms(dev, "client hotplug ret=%d\n", ret);
223222

224-
void exynos_drm_fbdev_fini(struct drm_device *dev)
225-
{
226-
struct drm_fb_helper *fb_helper = dev->fb_helper;
223+
drm_client_register(&fb_helper->client);
227224

228-
if (!fb_helper)
229-
return;
225+
return;
230226

231-
exynos_drm_fbdev_destroy(dev, fb_helper);
232-
drm_client_release(&fb_helper->client);
227+
err_drm_client_init:
233228
drm_fb_helper_unprepare(fb_helper);
234229
kfree(fb_helper);
235230
}
236-

drivers/gpu/drm/exynos/exynos_drm_fbdev.h

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,27 +12,11 @@
1212
#define _EXYNOS_DRM_FBDEV_H_
1313

1414
#ifdef CONFIG_DRM_FBDEV_EMULATION
15-
16-
int exynos_drm_fbdev_init(struct drm_device *dev);
17-
void exynos_drm_fbdev_fini(struct drm_device *dev);
18-
15+
void exynos_drm_fbdev_setup(struct drm_device *dev);
1916
#else
20-
21-
static inline int exynos_drm_fbdev_init(struct drm_device *dev)
22-
{
23-
return 0;
24-
}
25-
26-
static inline void exynos_drm_fbdev_fini(struct drm_device *dev)
17+
static inline void exynos_drm_fbdev_setup(struct drm_device *dev)
2718
{
2819
}
29-
30-
static inline void exynos_drm_fbdev_restore_mode(struct drm_device *dev)
31-
{
32-
}
33-
34-
#define exynos_drm_output_poll_changed (NULL)
35-
3620
#endif
3721

3822
#endif

0 commit comments

Comments
 (0)