1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17#include <drm/drmP.h>
18#include <drm/drm_crtc_helper.h>
19#include <drm/drm_gem.h>
20
21#include "xylon_crtc.h"
22#include "xylon_drv.h"
23#include "xylon_fb.h"
24#include "xylon_fbdev.h"
25
26#define fb_to_xylon_drm_fb(x) container_of(x, struct xylon_drm_fb, fb)
27
28struct xylon_drm_fb {
29 struct drm_framebuffer fb;
30 struct drm_gem_object *obj;
31};
32
33static void xylon_drm_fb_destroy(struct drm_framebuffer *fb)
34{
35 struct drm_gem_object *obj;
36 struct xylon_drm_fb *xfb = fb_to_xylon_drm_fb(fb);
37
38 drm_framebuffer_cleanup(fb);
39
40 obj = xfb->obj;
41 if (obj)
42 drm_gem_object_unreference_unlocked(obj);
43
44 kfree(xfb);
45}
46
47static int xylon_drm_fb_create_handle(struct drm_framebuffer *fb,
48 struct drm_file *file_priv,
49 unsigned int *handle)
50{
51 struct xylon_drm_fb *xfb = fb_to_xylon_drm_fb(fb);
52
53 return drm_gem_handle_create(file_priv, xfb->obj, handle);
54}
55
56static struct drm_framebuffer_funcs xylon_fb_funcs = {
57 .destroy = xylon_drm_fb_destroy,
58 .create_handle = xylon_drm_fb_create_handle,
59};
60
61struct drm_framebuffer *xylon_drm_fb_init(struct drm_device *dev,
62 struct drm_mode_fb_cmd2 *mode_cmd,
63 struct drm_gem_object *obj)
64{
65 struct drm_framebuffer *fb;
66 struct xylon_drm_fb *xfb;
67 int ret;
68
69 xfb = kzalloc(sizeof(*xfb), GFP_KERNEL);
70 if (!xfb) {
71 DRM_ERROR("failed allocate framebuffer\n");
72 return ERR_PTR(-ENOMEM);
73 }
74
75 xfb->obj = obj;
76
77 fb = &xfb->fb;
78
79 drm_helper_mode_fill_fb_struct(fb, mode_cmd);
80
81 ret = drm_framebuffer_init(dev, fb, &xylon_fb_funcs);
82 if (ret) {
83 DRM_ERROR("failed framebuffer init\n");
84 goto err;
85 }
86
87 return fb;
88
89err:
90 xylon_drm_fb_destroy(fb);
91
92 return ERR_PTR(ret);
93}
94
95struct drm_gem_object *xylon_drm_fb_get_gem_obj(struct drm_framebuffer *fb)
96{
97 struct xylon_drm_fb *xfb = fb_to_xylon_drm_fb(fb);
98
99 return xfb->obj;
100}
101
102static struct drm_framebuffer *
103xylon_drm_fb_create(struct drm_device *dev, struct drm_file *file_priv,
104 struct drm_mode_fb_cmd2 *mode_cmd)
105{
106 struct drm_gem_object *obj;
107 struct xylon_drm_device *xdev = dev->dev_private;
108 bool res;
109
110 res = xylon_drm_crtc_check_format(xdev->crtc, mode_cmd->pixel_format);
111 if (!res) {
112 DRM_ERROR("unsupported pixel format %08x\n",
113 mode_cmd->pixel_format);
114 return ERR_PTR(-EINVAL);
115 }
116
117 obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[0]);
118 if (!obj)
119 return ERR_PTR(-EINVAL);
120
121 return xylon_drm_fb_init(dev, mode_cmd, obj);
122}
123
124static void xylon_drm_output_poll_changed(struct drm_device *dev)
125{
126 struct xylon_drm_device *xdev = dev->dev_private;
127
128 xylon_drm_fbdev_hotplug_event(xdev->fbdev);
129}
130
131static const struct drm_mode_config_funcs xylon_drm_mode_config_funcs = {
132 .fb_create = xylon_drm_fb_create,
133 .output_poll_changed = xylon_drm_output_poll_changed,
134};
135
136void xylon_drm_mode_config_init(struct drm_device *dev)
137{
138 struct xylon_drm_device *xdev = dev->dev_private;
139
140 xylon_drm_crtc_get_fix_parameters(xdev->crtc);
141
142 dev->mode_config.funcs = &xylon_drm_mode_config_funcs;
143}
144