Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/arm/nvidia/drm2/tegra_fb.c
39483 views
1
/*-
2
* Copyright (c) 2016 Michal Meloun
3
* All rights reserved.
4
*
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
7
* are met:
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer.
10
* 2. Redistributions in binary form must reproduce the above copyright
11
* notice, this list of conditions and the following disclaimer in the
12
* documentation and/or other materials provided with the distribution.
13
*
14
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
* SUCH DAMAGE.
25
*/
26
27
#include <sys/param.h>
28
#include <sys/systm.h>
29
#include <sys/bus.h>
30
#include <sys/kernel.h>
31
#include <sys/malloc.h>
32
33
#include <machine/bus.h>
34
35
#include <dev/clk/clk.h>
36
#include <dev/drm2/drmP.h>
37
#include <dev/drm2/drm_crtc_helper.h>
38
#include <dev/drm2/drm_fb_helper.h>
39
40
#include <arm/nvidia/drm2/tegra_drm.h>
41
42
static void
43
fb_destroy(struct drm_framebuffer *drm_fb)
44
{
45
struct tegra_fb *fb;
46
struct tegra_bo *bo;
47
unsigned int i;
48
49
fb = container_of(drm_fb, struct tegra_fb, drm_fb);
50
for (i = 0; i < fb->nplanes; i++) {
51
bo = fb->planes[i];
52
if (bo != NULL)
53
drm_gem_object_unreference_unlocked(&bo->gem_obj);
54
}
55
56
drm_framebuffer_cleanup(drm_fb);
57
free(fb->planes, DRM_MEM_DRIVER);
58
}
59
60
static int
61
fb_create_handle(struct drm_framebuffer *drm_fb, struct drm_file *file,
62
unsigned int *handle)
63
{
64
struct tegra_fb *fb;
65
int rv;
66
67
fb = container_of(drm_fb, struct tegra_fb, drm_fb);
68
rv = drm_gem_handle_create(file, &fb->planes[0]->gem_obj, handle);
69
return (rv);
70
}
71
72
/* XXX Probably not needed */
73
static int
74
fb_dirty(struct drm_framebuffer *fb, struct drm_file *file_priv,
75
unsigned flags, unsigned color, struct drm_clip_rect *clips, unsigned num_clips)
76
{
77
78
return (0);
79
}
80
81
static const struct drm_framebuffer_funcs fb_funcs = {
82
.destroy = fb_destroy,
83
.create_handle = fb_create_handle,
84
.dirty = fb_dirty,
85
};
86
87
static int
88
fb_alloc(struct drm_device *drm, struct drm_mode_fb_cmd2 *mode_cmd,
89
struct tegra_bo **planes, int num_planes, struct tegra_fb **res_fb)
90
{
91
struct tegra_fb *fb;
92
int i;
93
int rv;
94
95
fb = malloc(sizeof(*fb), DRM_MEM_DRIVER, M_WAITOK | M_ZERO);
96
fb->planes = malloc(num_planes * sizeof(*fb->planes), DRM_MEM_DRIVER,
97
M_WAITOK | M_ZERO);
98
fb->nplanes = num_planes;
99
100
drm_helper_mode_fill_fb_struct(&fb->drm_fb, mode_cmd);
101
for (i = 0; i < fb->nplanes; i++)
102
fb->planes[i] = planes[i];
103
rv = drm_framebuffer_init(drm, &fb->drm_fb, &fb_funcs);
104
if (rv < 0) {
105
device_printf(drm->dev,
106
"Cannot initialize frame buffer %d\n", rv);
107
free(fb->planes, DRM_MEM_DRIVER);
108
return (rv);
109
}
110
*res_fb = fb;
111
return (0);
112
}
113
114
static int
115
tegra_fb_probe(struct drm_fb_helper *helper,
116
struct drm_fb_helper_surface_size *sizes)
117
{
118
u_int bpp, size;
119
struct tegra_drm *drm;
120
struct tegra_fb *fb;
121
struct fb_info *info;
122
struct tegra_bo *bo;
123
struct drm_mode_fb_cmd2 mode_cmd;
124
struct drm_device *drm_dev;
125
int rv;
126
127
if (helper->fb != NULL)
128
return (0);
129
130
DRM_DEBUG_KMS("surface: %d x %d (bpp: %d)\n", sizes->surface_width,
131
sizes->surface_height, sizes->surface_bpp);
132
133
drm_dev = helper->dev;
134
fb = container_of(helper, struct tegra_fb, fb_helper);
135
drm = container_of(drm_dev, struct tegra_drm, drm_dev);
136
bpp = (sizes->surface_bpp + 7) / 8;
137
138
/* Create mode_cmd */
139
memset(&mode_cmd, 0, sizeof(mode_cmd));
140
mode_cmd.width = sizes->surface_width;
141
mode_cmd.height = sizes->surface_height;
142
mode_cmd.pitches[0] = roundup(sizes->surface_width * bpp,
143
drm->pitch_align);
144
mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
145
sizes->surface_depth);
146
size = mode_cmd.pitches[0] * mode_cmd.height;
147
148
DRM_LOCK(drm_dev);
149
rv = tegra_bo_create(drm_dev, size, &bo);
150
DRM_UNLOCK(drm_dev);
151
if (rv != 0)
152
return (rv);
153
154
info = framebuffer_alloc();
155
if (info == NULL) {
156
device_printf(drm_dev->dev,
157
"Cannot allocate DRM framebuffer info.\n");
158
rv = -ENOMEM;
159
goto err_object;
160
}
161
162
rv = fb_alloc(drm_dev, &mode_cmd, &bo, 1, &fb);
163
if (rv != 0) {
164
device_printf(drm_dev->dev,
165
"Cannot allocate DRM framebuffer.\n");
166
goto err_fb;
167
}
168
helper->fb = &fb->drm_fb;
169
helper->fbdev = info;
170
171
/* Fill FB info */
172
info->fb_vbase = bo->vbase;
173
info->fb_pbase = bo->pbase;
174
info->fb_size = size;
175
info->fb_bpp = sizes->surface_bpp;
176
drm_fb_helper_fill_fix(info, fb->drm_fb.pitches[0], fb->drm_fb.depth);
177
drm_fb_helper_fill_var(info, helper, fb->drm_fb.width,
178
fb->drm_fb.height);
179
180
DRM_DEBUG_KMS("allocated %dx%d (s %dbits) fb size: %d, bo %p\n",
181
fb->drm_fb.width, fb->drm_fb.height, fb->drm_fb.depth,
182
size, bo);
183
return (1);
184
err_fb:
185
drm_gem_object_unreference_unlocked(&bo->gem_obj);
186
framebuffer_release(info);
187
err_object:
188
drm_gem_object_release(&bo->gem_obj);
189
return (rv);
190
}
191
192
static struct drm_fb_helper_funcs fb_helper_funcs = {
193
.fb_probe = tegra_fb_probe,
194
};
195
196
/*
197
* Exported functions
198
*/
199
struct fb_info *
200
tegra_drm_fb_getinfo(struct drm_device *drm_dev)
201
{
202
struct tegra_fb *fb;
203
struct tegra_drm *drm;
204
205
drm = container_of(drm_dev, struct tegra_drm, drm_dev);
206
fb = drm->fb;
207
if (fb == NULL)
208
return (NULL);
209
return (fb->fb_helper.fbdev);
210
}
211
212
struct tegra_bo *
213
tegra_fb_get_plane(struct tegra_fb *fb, int idx)
214
{
215
216
if (idx >= drm_format_num_planes(fb->drm_fb.pixel_format))
217
return (NULL);
218
if (idx >= fb->nplanes)
219
return (NULL);
220
return (fb->planes[idx]);
221
}
222
223
int
224
tegra_drm_fb_init(struct drm_device *drm_dev)
225
{
226
struct tegra_fb *fb;
227
struct tegra_drm *drm;
228
int rv;
229
230
drm = drm_dev->dev_private;
231
drm = container_of(drm_dev, struct tegra_drm, drm_dev);
232
fb = malloc(sizeof(*fb), DRM_MEM_DRIVER, M_WAITOK | M_ZERO);
233
drm->fb = fb;
234
235
fb->fb_helper.funcs = &fb_helper_funcs;
236
rv = drm_fb_helper_init(drm_dev, &fb->fb_helper,
237
drm_dev->mode_config.num_crtc, drm_dev->mode_config.num_connector);
238
if (rv != 0) {
239
device_printf(drm_dev->dev,
240
"Cannot initialize frame buffer %d\n", rv);
241
return (rv);
242
}
243
244
rv = drm_fb_helper_single_add_all_connectors(&fb->fb_helper);
245
if (rv != 0) {
246
device_printf(drm_dev->dev, "Cannot add all connectors: %d\n",
247
rv);
248
goto err_fini;
249
}
250
251
rv = drm_fb_helper_initial_config(&fb->fb_helper, 32);
252
if (rv != 0) {
253
device_printf(drm_dev->dev,
254
"Cannot set initial config: %d\n", rv);
255
goto err_fini;
256
}
257
/* XXXX Setup initial mode for FB */
258
/* drm_fb_helper_set_par(fb->fb_helper.fbdev); */
259
return 0;
260
261
err_fini:
262
drm_fb_helper_fini(&fb->fb_helper);
263
return (rv);
264
}
265
266
int
267
tegra_drm_fb_create(struct drm_device *drm, struct drm_file *file,
268
struct drm_mode_fb_cmd2 *cmd, struct drm_framebuffer **fb_res)
269
{
270
int hsub, vsub, i;
271
int width, height, size, bpp;
272
struct tegra_bo *planes[4];
273
struct drm_gem_object *gem_obj;
274
struct tegra_fb *fb;
275
int rv, nplanes;
276
277
hsub = drm_format_horz_chroma_subsampling(cmd->pixel_format);
278
vsub = drm_format_vert_chroma_subsampling(cmd->pixel_format);
279
280
nplanes = drm_format_num_planes(cmd->pixel_format);
281
for (i = 0; i < nplanes; i++) {
282
width = cmd->width;
283
height = cmd->height;
284
if (i != 0) {
285
width /= hsub;
286
height /= vsub;
287
}
288
gem_obj = drm_gem_object_lookup(drm, file, cmd->handles[i]);
289
if (gem_obj == NULL) {
290
rv = -ENXIO;
291
goto fail;
292
}
293
294
bpp = drm_format_plane_cpp(cmd->pixel_format, i);
295
size = (height - 1) * cmd->pitches[i] +
296
width * bpp + cmd->offsets[i];
297
if (gem_obj->size < size) {
298
rv = -EINVAL;
299
goto fail;
300
}
301
planes[i] = container_of(gem_obj, struct tegra_bo, gem_obj);
302
}
303
304
rv = fb_alloc(drm, cmd, planes, nplanes, &fb);
305
if (rv != 0)
306
goto fail;
307
308
*fb_res = &fb->drm_fb;
309
return (0);
310
311
fail:
312
while (i--)
313
drm_gem_object_unreference_unlocked(&planes[i]->gem_obj);
314
return (rv);
315
}
316
317
void
318
tegra_drm_fb_destroy(struct drm_device *drm_dev)
319
{
320
struct fb_info *info;
321
struct tegra_fb *fb;
322
struct tegra_drm *drm;
323
324
drm = container_of(drm_dev, struct tegra_drm, drm_dev);
325
fb = drm->fb;
326
if (fb == NULL)
327
return;
328
info = fb->fb_helper.fbdev;
329
drm_framebuffer_remove(&fb->drm_fb);
330
framebuffer_release(info);
331
drm_fb_helper_fini(&fb->fb_helper);
332
drm_framebuffer_cleanup(&fb->drm_fb);
333
free(fb, DRM_MEM_DRIVER);
334
drm->fb = NULL;
335
}
336
337