Merge branch 'drm-tda998x-devel' of git://git.armlinux.org.uk/~rmk/linux-arm into...
[deliverable/linux.git] / drivers / gpu / drm / mediatek / mtk_drm_fb.c
CommitLineData
119f5173
CH
1/*
2 * Copyright (c) 2015 MediaTek Inc.
3 *
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.
7 *
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.
12 */
13
14#include <drm/drmP.h>
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>
20
21#include "mtk_drm_drv.h"
22#include "mtk_drm_fb.h"
23#include "mtk_drm_gem.h"
24
25/*
26 * mtk specific framebuffer structure.
27 *
28 * @fb: drm framebuffer object.
29 * @gem_obj: array of gem objects.
30 */
31struct mtk_drm_fb {
32 struct drm_framebuffer base;
33 /* For now we only support a single plane */
34 struct drm_gem_object *gem_obj;
35};
36
37#define to_mtk_fb(x) container_of(x, struct mtk_drm_fb, base)
38
39struct drm_gem_object *mtk_fb_get_gem_obj(struct drm_framebuffer *fb)
40{
41 struct mtk_drm_fb *mtk_fb = to_mtk_fb(fb);
42
43 return mtk_fb->gem_obj;
44}
45
46static int mtk_drm_fb_create_handle(struct drm_framebuffer *fb,
47 struct drm_file *file_priv,
48 unsigned int *handle)
49{
50 struct mtk_drm_fb *mtk_fb = to_mtk_fb(fb);
51
52 return drm_gem_handle_create(file_priv, mtk_fb->gem_obj, handle);
53}
54
55static void mtk_drm_fb_destroy(struct drm_framebuffer *fb)
56{
57 struct mtk_drm_fb *mtk_fb = to_mtk_fb(fb);
58
59 drm_framebuffer_cleanup(fb);
60
61 drm_gem_object_unreference_unlocked(mtk_fb->gem_obj);
62
63 kfree(mtk_fb);
64}
65
66static const struct drm_framebuffer_funcs mtk_drm_fb_funcs = {
67 .create_handle = mtk_drm_fb_create_handle,
68 .destroy = mtk_drm_fb_destroy,
69};
70
71static 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)
74{
75 struct mtk_drm_fb *mtk_fb;
76 int ret;
77
78 if (drm_format_num_planes(mode->pixel_format) != 1)
79 return ERR_PTR(-EINVAL);
80
81 mtk_fb = kzalloc(sizeof(*mtk_fb), GFP_KERNEL);
82 if (!mtk_fb)
83 return ERR_PTR(-ENOMEM);
84
85 drm_helper_mode_fill_fb_struct(&mtk_fb->base, mode);
86
87 mtk_fb->gem_obj = obj;
88
89 ret = drm_framebuffer_init(dev, &mtk_fb->base, &mtk_drm_fb_funcs);
90 if (ret) {
91 DRM_ERROR("failed to initialize framebuffer\n");
92 kfree(mtk_fb);
93 return ERR_PTR(ret);
94 }
95
96 return mtk_fb;
97}
98
99/*
100 * Wait for any exclusive fence in fb's gem object's reservation object.
101 *
102 * Returns -ERESTARTSYS if interrupted, else 0.
103 */
104int mtk_fb_wait(struct drm_framebuffer *fb)
105{
106 struct drm_gem_object *gem;
107 struct reservation_object *resv;
108 long ret;
109
110 if (!fb)
111 return 0;
112
113 gem = mtk_fb_get_gem_obj(fb);
114 if (!gem || !gem->dma_buf || !gem->dma_buf->resv)
115 return 0;
116
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))
122 return ret;
123
124 return 0;
125}
126
127struct drm_framebuffer *mtk_drm_mode_fb_create(struct drm_device *dev,
128 struct drm_file *file,
129 const struct drm_mode_fb_cmd2 *cmd)
130{
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;
136 int ret;
137
138 if (drm_format_num_planes(cmd->pixel_format) != 1)
139 return ERR_PTR(-EINVAL);
140
de4ae068 141 gem = drm_gem_object_lookup(file, cmd->handles[0]);
119f5173
CH
142 if (!gem)
143 return ERR_PTR(-ENOENT);
144
145 bpp = drm_format_plane_cpp(cmd->pixel_format, 0);
146 size = (height - 1) * cmd->pitches[0] + width * bpp;
147 size += cmd->offsets[0];
148
149 if (gem->size < size) {
150 ret = -EINVAL;
151 goto unreference;
152 }
153
154 mtk_fb = mtk_drm_framebuffer_init(dev, cmd, gem);
155 if (IS_ERR(mtk_fb)) {
156 ret = PTR_ERR(mtk_fb);
157 goto unreference;
158 }
159
160 return &mtk_fb->base;
161
162unreference:
163 drm_gem_object_unreference_unlocked(gem);
164 return ERR_PTR(ret);
165}
This page took 0.049691 seconds and 5 git commands to generate.