2 * Copyright (c) 2015 MediaTek Inc.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
15 #include <drm/drm_crtc_helper.h>
16 #include <drm/drm_fb_helper.h>
17 #include <drm/drm_gem.h>
18 #include <linux/dma-buf.h>
19 #include <linux/reservation.h>
21 #include "mtk_drm_drv.h"
22 #include "mtk_drm_fb.h"
23 #include "mtk_drm_gem.h"
26 * mtk specific framebuffer structure.
28 * @fb: drm framebuffer object.
29 * @gem_obj: array of gem objects.
32 struct drm_framebuffer base
;
33 /* For now we only support a single plane */
34 struct drm_gem_object
*gem_obj
;
37 #define to_mtk_fb(x) container_of(x, struct mtk_drm_fb, base)
39 struct drm_gem_object
*mtk_fb_get_gem_obj(struct drm_framebuffer
*fb
)
41 struct mtk_drm_fb
*mtk_fb
= to_mtk_fb(fb
);
43 return mtk_fb
->gem_obj
;
46 static int mtk_drm_fb_create_handle(struct drm_framebuffer
*fb
,
47 struct drm_file
*file_priv
,
50 struct mtk_drm_fb
*mtk_fb
= to_mtk_fb(fb
);
52 return drm_gem_handle_create(file_priv
, mtk_fb
->gem_obj
, handle
);
55 static void mtk_drm_fb_destroy(struct drm_framebuffer
*fb
)
57 struct mtk_drm_fb
*mtk_fb
= to_mtk_fb(fb
);
59 drm_framebuffer_cleanup(fb
);
61 drm_gem_object_unreference_unlocked(mtk_fb
->gem_obj
);
66 static const struct drm_framebuffer_funcs mtk_drm_fb_funcs
= {
67 .create_handle
= mtk_drm_fb_create_handle
,
68 .destroy
= mtk_drm_fb_destroy
,
71 static struct mtk_drm_fb
*mtk_drm_framebuffer_init(struct drm_device
*dev
,
72 const struct drm_mode_fb_cmd2
*mode
,
73 struct drm_gem_object
*obj
)
75 struct mtk_drm_fb
*mtk_fb
;
78 if (drm_format_num_planes(mode
->pixel_format
) != 1)
79 return ERR_PTR(-EINVAL
);
81 mtk_fb
= kzalloc(sizeof(*mtk_fb
), GFP_KERNEL
);
83 return ERR_PTR(-ENOMEM
);
85 drm_helper_mode_fill_fb_struct(dev
, &mtk_fb
->base
, mode
);
87 mtk_fb
->gem_obj
= obj
;
89 ret
= drm_framebuffer_init(dev
, &mtk_fb
->base
, &mtk_drm_fb_funcs
);
91 DRM_ERROR("failed to initialize framebuffer\n");
100 * Wait for any exclusive fence in fb's gem object's reservation object.
102 * Returns -ERESTARTSYS if interrupted, else 0.
104 int mtk_fb_wait(struct drm_framebuffer
*fb
)
106 struct drm_gem_object
*gem
;
107 struct reservation_object
*resv
;
113 gem
= mtk_fb_get_gem_obj(fb
);
114 if (!gem
|| !gem
->dma_buf
|| !gem
->dma_buf
->resv
)
117 resv
= gem
->dma_buf
->resv
;
118 ret
= reservation_object_wait_timeout_rcu(resv
, false, true,
119 MAX_SCHEDULE_TIMEOUT
);
120 /* MAX_SCHEDULE_TIMEOUT on success, -ERESTARTSYS if interrupted */
121 if (WARN_ON(ret
< 0))
127 struct drm_framebuffer
*mtk_drm_mode_fb_create(struct drm_device
*dev
,
128 struct drm_file
*file
,
129 const struct drm_mode_fb_cmd2
*cmd
)
131 struct mtk_drm_fb
*mtk_fb
;
132 struct drm_gem_object
*gem
;
133 unsigned int width
= cmd
->width
;
134 unsigned int height
= cmd
->height
;
135 unsigned int size
, bpp
;
138 if (drm_format_num_planes(cmd
->pixel_format
) != 1)
139 return ERR_PTR(-EINVAL
);
141 gem
= drm_gem_object_lookup(file
, cmd
->handles
[0]);
143 return ERR_PTR(-ENOENT
);
145 bpp
= drm_format_plane_cpp(cmd
->pixel_format
, 0);
146 size
= (height
- 1) * cmd
->pitches
[0] + width
* bpp
;
147 size
+= cmd
->offsets
[0];
149 if (gem
->size
< size
) {
154 mtk_fb
= mtk_drm_framebuffer_init(dev
, cmd
, gem
);
155 if (IS_ERR(mtk_fb
)) {
156 ret
= PTR_ERR(mtk_fb
);
160 return &mtk_fb
->base
;
163 drm_gem_object_unreference_unlocked(gem
);