xref: /linux/drivers/gpu/drm/tegra/fb.c (revision 3ad0876554cafa368f574d4d408468510543e9ff)
1 /*
2  * Copyright (C) 2012-2013 Avionic Design GmbH
3  * Copyright (C) 2012 NVIDIA CORPORATION.  All rights reserved.
4  *
5  * Based on the KMS/FB CMA helpers
6  *   Copyright (C) 2012 Analog Device Inc.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12 
13 #include <linux/console.h>
14 
15 #include "drm.h"
16 #include "gem.h"
17 
18 static inline struct tegra_fb *to_tegra_fb(struct drm_framebuffer *fb)
19 {
20 	return container_of(fb, struct tegra_fb, base);
21 }
22 
23 #ifdef CONFIG_DRM_FBDEV_EMULATION
24 static inline struct tegra_fbdev *to_tegra_fbdev(struct drm_fb_helper *helper)
25 {
26 	return container_of(helper, struct tegra_fbdev, base);
27 }
28 #endif
29 
30 struct tegra_bo *tegra_fb_get_plane(struct drm_framebuffer *framebuffer,
31 				    unsigned int index)
32 {
33 	struct tegra_fb *fb = to_tegra_fb(framebuffer);
34 
35 	if (index >= framebuffer->format->num_planes)
36 		return NULL;
37 
38 	return fb->planes[index];
39 }
40 
41 bool tegra_fb_is_bottom_up(struct drm_framebuffer *framebuffer)
42 {
43 	struct tegra_fb *fb = to_tegra_fb(framebuffer);
44 
45 	if (fb->planes[0]->flags & TEGRA_BO_BOTTOM_UP)
46 		return true;
47 
48 	return false;
49 }
50 
51 int tegra_fb_get_tiling(struct drm_framebuffer *framebuffer,
52 			struct tegra_bo_tiling *tiling)
53 {
54 	struct tegra_fb *fb = to_tegra_fb(framebuffer);
55 	uint64_t modifier = fb->base.modifier;
56 
57 	switch (modifier) {
58 	case DRM_FORMAT_MOD_LINEAR:
59 		tiling->mode = TEGRA_BO_TILING_MODE_PITCH;
60 		tiling->value = 0;
61 		break;
62 
63 	case DRM_FORMAT_MOD_NVIDIA_TEGRA_TILED:
64 		tiling->mode = TEGRA_BO_TILING_MODE_TILED;
65 		tiling->value = 0;
66 		break;
67 
68 	case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(0):
69 		tiling->mode = TEGRA_BO_TILING_MODE_BLOCK;
70 		tiling->value = 0;
71 		break;
72 
73 	case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(1):
74 		tiling->mode = TEGRA_BO_TILING_MODE_BLOCK;
75 		tiling->value = 1;
76 		break;
77 
78 	case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(2):
79 		tiling->mode = TEGRA_BO_TILING_MODE_BLOCK;
80 		tiling->value = 2;
81 		break;
82 
83 	case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(3):
84 		tiling->mode = TEGRA_BO_TILING_MODE_BLOCK;
85 		tiling->value = 3;
86 		break;
87 
88 	case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(4):
89 		tiling->mode = TEGRA_BO_TILING_MODE_BLOCK;
90 		tiling->value = 4;
91 		break;
92 
93 	case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(5):
94 		tiling->mode = TEGRA_BO_TILING_MODE_BLOCK;
95 		tiling->value = 5;
96 		break;
97 
98 	default:
99 		return -EINVAL;
100 	}
101 
102 	return 0;
103 }
104 
105 static void tegra_fb_destroy(struct drm_framebuffer *framebuffer)
106 {
107 	struct tegra_fb *fb = to_tegra_fb(framebuffer);
108 	unsigned int i;
109 
110 	for (i = 0; i < fb->num_planes; i++) {
111 		struct tegra_bo *bo = fb->planes[i];
112 
113 		if (bo) {
114 			if (bo->pages)
115 				vunmap(bo->vaddr);
116 
117 			drm_gem_object_put_unlocked(&bo->gem);
118 		}
119 	}
120 
121 	drm_framebuffer_cleanup(framebuffer);
122 	kfree(fb->planes);
123 	kfree(fb);
124 }
125 
126 static int tegra_fb_create_handle(struct drm_framebuffer *framebuffer,
127 				  struct drm_file *file, unsigned int *handle)
128 {
129 	struct tegra_fb *fb = to_tegra_fb(framebuffer);
130 
131 	return drm_gem_handle_create(file, &fb->planes[0]->gem, handle);
132 }
133 
134 static const struct drm_framebuffer_funcs tegra_fb_funcs = {
135 	.destroy = tegra_fb_destroy,
136 	.create_handle = tegra_fb_create_handle,
137 };
138 
139 static struct tegra_fb *tegra_fb_alloc(struct drm_device *drm,
140 				       const struct drm_mode_fb_cmd2 *mode_cmd,
141 				       struct tegra_bo **planes,
142 				       unsigned int num_planes)
143 {
144 	struct tegra_fb *fb;
145 	unsigned int i;
146 	int err;
147 
148 	fb = kzalloc(sizeof(*fb), GFP_KERNEL);
149 	if (!fb)
150 		return ERR_PTR(-ENOMEM);
151 
152 	fb->planes = kzalloc(num_planes * sizeof(*planes), GFP_KERNEL);
153 	if (!fb->planes) {
154 		kfree(fb);
155 		return ERR_PTR(-ENOMEM);
156 	}
157 
158 	fb->num_planes = num_planes;
159 
160 	drm_helper_mode_fill_fb_struct(drm, &fb->base, mode_cmd);
161 
162 	for (i = 0; i < fb->num_planes; i++)
163 		fb->planes[i] = planes[i];
164 
165 	err = drm_framebuffer_init(drm, &fb->base, &tegra_fb_funcs);
166 	if (err < 0) {
167 		dev_err(drm->dev, "failed to initialize framebuffer: %d\n",
168 			err);
169 		kfree(fb->planes);
170 		kfree(fb);
171 		return ERR_PTR(err);
172 	}
173 
174 	return fb;
175 }
176 
177 struct drm_framebuffer *tegra_fb_create(struct drm_device *drm,
178 					struct drm_file *file,
179 					const struct drm_mode_fb_cmd2 *cmd)
180 {
181 	unsigned int hsub, vsub, i;
182 	struct tegra_bo *planes[4];
183 	struct drm_gem_object *gem;
184 	struct tegra_fb *fb;
185 	int err;
186 
187 	hsub = drm_format_horz_chroma_subsampling(cmd->pixel_format);
188 	vsub = drm_format_vert_chroma_subsampling(cmd->pixel_format);
189 
190 	for (i = 0; i < drm_format_num_planes(cmd->pixel_format); i++) {
191 		unsigned int width = cmd->width / (i ? hsub : 1);
192 		unsigned int height = cmd->height / (i ? vsub : 1);
193 		unsigned int size, bpp;
194 
195 		gem = drm_gem_object_lookup(file, cmd->handles[i]);
196 		if (!gem) {
197 			err = -ENXIO;
198 			goto unreference;
199 		}
200 
201 		bpp = drm_format_plane_cpp(cmd->pixel_format, i);
202 
203 		size = (height - 1) * cmd->pitches[i] +
204 		       width * bpp + cmd->offsets[i];
205 
206 		if (gem->size < size) {
207 			err = -EINVAL;
208 			goto unreference;
209 		}
210 
211 		planes[i] = to_tegra_bo(gem);
212 	}
213 
214 	fb = tegra_fb_alloc(drm, cmd, planes, i);
215 	if (IS_ERR(fb)) {
216 		err = PTR_ERR(fb);
217 		goto unreference;
218 	}
219 
220 	return &fb->base;
221 
222 unreference:
223 	while (i--)
224 		drm_gem_object_put_unlocked(&planes[i]->gem);
225 
226 	return ERR_PTR(err);
227 }
228 
229 #ifdef CONFIG_DRM_FBDEV_EMULATION
230 static int tegra_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
231 {
232 	struct drm_fb_helper *helper = info->par;
233 	struct tegra_bo *bo;
234 	int err;
235 
236 	bo = tegra_fb_get_plane(helper->fb, 0);
237 
238 	err = drm_gem_mmap_obj(&bo->gem, bo->gem.size, vma);
239 	if (err < 0)
240 		return err;
241 
242 	return __tegra_gem_mmap(&bo->gem, vma);
243 }
244 
245 static struct fb_ops tegra_fb_ops = {
246 	.owner = THIS_MODULE,
247 	DRM_FB_HELPER_DEFAULT_OPS,
248 	.fb_fillrect = drm_fb_helper_sys_fillrect,
249 	.fb_copyarea = drm_fb_helper_sys_copyarea,
250 	.fb_imageblit = drm_fb_helper_sys_imageblit,
251 	.fb_mmap = tegra_fb_mmap,
252 };
253 
254 static int tegra_fbdev_probe(struct drm_fb_helper *helper,
255 			     struct drm_fb_helper_surface_size *sizes)
256 {
257 	struct tegra_fbdev *fbdev = to_tegra_fbdev(helper);
258 	struct tegra_drm *tegra = helper->dev->dev_private;
259 	struct drm_device *drm = helper->dev;
260 	struct drm_mode_fb_cmd2 cmd = { 0 };
261 	unsigned int bytes_per_pixel;
262 	struct drm_framebuffer *fb;
263 	unsigned long offset;
264 	struct fb_info *info;
265 	struct tegra_bo *bo;
266 	size_t size;
267 	int err;
268 
269 	bytes_per_pixel = DIV_ROUND_UP(sizes->surface_bpp, 8);
270 
271 	cmd.width = sizes->surface_width;
272 	cmd.height = sizes->surface_height;
273 	cmd.pitches[0] = round_up(sizes->surface_width * bytes_per_pixel,
274 				  tegra->pitch_align);
275 
276 	cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
277 						     sizes->surface_depth);
278 
279 	size = cmd.pitches[0] * cmd.height;
280 
281 	bo = tegra_bo_create(drm, size, 0);
282 	if (IS_ERR(bo))
283 		return PTR_ERR(bo);
284 
285 	info = drm_fb_helper_alloc_fbi(helper);
286 	if (IS_ERR(info)) {
287 		dev_err(drm->dev, "failed to allocate framebuffer info\n");
288 		drm_gem_object_put_unlocked(&bo->gem);
289 		return PTR_ERR(info);
290 	}
291 
292 	fbdev->fb = tegra_fb_alloc(drm, &cmd, &bo, 1);
293 	if (IS_ERR(fbdev->fb)) {
294 		err = PTR_ERR(fbdev->fb);
295 		dev_err(drm->dev, "failed to allocate DRM framebuffer: %d\n",
296 			err);
297 		drm_gem_object_put_unlocked(&bo->gem);
298 		return PTR_ERR(fbdev->fb);
299 	}
300 
301 	fb = &fbdev->fb->base;
302 	helper->fb = fb;
303 	helper->fbdev = info;
304 
305 	info->par = helper;
306 	info->flags = FBINFO_FLAG_DEFAULT;
307 	info->fbops = &tegra_fb_ops;
308 
309 	drm_fb_helper_fill_fix(info, fb->pitches[0], fb->format->depth);
310 	drm_fb_helper_fill_var(info, helper, fb->width, fb->height);
311 
312 	offset = info->var.xoffset * bytes_per_pixel +
313 		 info->var.yoffset * fb->pitches[0];
314 
315 	if (bo->pages) {
316 		bo->vaddr = vmap(bo->pages, bo->num_pages, VM_MAP,
317 				 pgprot_writecombine(PAGE_KERNEL));
318 		if (!bo->vaddr) {
319 			dev_err(drm->dev, "failed to vmap() framebuffer\n");
320 			err = -ENOMEM;
321 			goto destroy;
322 		}
323 	}
324 
325 	drm->mode_config.fb_base = (resource_size_t)bo->paddr;
326 	info->screen_base = (void __iomem *)bo->vaddr + offset;
327 	info->screen_size = size;
328 	info->fix.smem_start = (unsigned long)(bo->paddr + offset);
329 	info->fix.smem_len = size;
330 
331 	return 0;
332 
333 destroy:
334 	drm_framebuffer_remove(fb);
335 	return err;
336 }
337 
338 static const struct drm_fb_helper_funcs tegra_fb_helper_funcs = {
339 	.fb_probe = tegra_fbdev_probe,
340 };
341 
342 static struct tegra_fbdev *tegra_fbdev_create(struct drm_device *drm)
343 {
344 	struct tegra_fbdev *fbdev;
345 
346 	fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL);
347 	if (!fbdev) {
348 		dev_err(drm->dev, "failed to allocate DRM fbdev\n");
349 		return ERR_PTR(-ENOMEM);
350 	}
351 
352 	drm_fb_helper_prepare(drm, &fbdev->base, &tegra_fb_helper_funcs);
353 
354 	return fbdev;
355 }
356 
357 static void tegra_fbdev_free(struct tegra_fbdev *fbdev)
358 {
359 	kfree(fbdev);
360 }
361 
362 static int tegra_fbdev_init(struct tegra_fbdev *fbdev,
363 			    unsigned int preferred_bpp,
364 			    unsigned int num_crtc,
365 			    unsigned int max_connectors)
366 {
367 	struct drm_device *drm = fbdev->base.dev;
368 	int err;
369 
370 	err = drm_fb_helper_init(drm, &fbdev->base, max_connectors);
371 	if (err < 0) {
372 		dev_err(drm->dev, "failed to initialize DRM FB helper: %d\n",
373 			err);
374 		return err;
375 	}
376 
377 	err = drm_fb_helper_single_add_all_connectors(&fbdev->base);
378 	if (err < 0) {
379 		dev_err(drm->dev, "failed to add connectors: %d\n", err);
380 		goto fini;
381 	}
382 
383 	err = drm_fb_helper_initial_config(&fbdev->base, preferred_bpp);
384 	if (err < 0) {
385 		dev_err(drm->dev, "failed to set initial configuration: %d\n",
386 			err);
387 		goto fini;
388 	}
389 
390 	return 0;
391 
392 fini:
393 	drm_fb_helper_fini(&fbdev->base);
394 	return err;
395 }
396 
397 static void tegra_fbdev_exit(struct tegra_fbdev *fbdev)
398 {
399 	drm_fb_helper_unregister_fbi(&fbdev->base);
400 
401 	if (fbdev->fb)
402 		drm_framebuffer_remove(&fbdev->fb->base);
403 
404 	drm_fb_helper_fini(&fbdev->base);
405 	tegra_fbdev_free(fbdev);
406 }
407 #endif
408 
409 int tegra_drm_fb_prepare(struct drm_device *drm)
410 {
411 #ifdef CONFIG_DRM_FBDEV_EMULATION
412 	struct tegra_drm *tegra = drm->dev_private;
413 
414 	tegra->fbdev = tegra_fbdev_create(drm);
415 	if (IS_ERR(tegra->fbdev))
416 		return PTR_ERR(tegra->fbdev);
417 #endif
418 
419 	return 0;
420 }
421 
422 void tegra_drm_fb_free(struct drm_device *drm)
423 {
424 #ifdef CONFIG_DRM_FBDEV_EMULATION
425 	struct tegra_drm *tegra = drm->dev_private;
426 
427 	tegra_fbdev_free(tegra->fbdev);
428 #endif
429 }
430 
431 int tegra_drm_fb_init(struct drm_device *drm)
432 {
433 #ifdef CONFIG_DRM_FBDEV_EMULATION
434 	struct tegra_drm *tegra = drm->dev_private;
435 	int err;
436 
437 	err = tegra_fbdev_init(tegra->fbdev, 32, drm->mode_config.num_crtc,
438 			       drm->mode_config.num_connector);
439 	if (err < 0)
440 		return err;
441 #endif
442 
443 	return 0;
444 }
445 
446 void tegra_drm_fb_exit(struct drm_device *drm)
447 {
448 #ifdef CONFIG_DRM_FBDEV_EMULATION
449 	struct tegra_drm *tegra = drm->dev_private;
450 
451 	tegra_fbdev_exit(tegra->fbdev);
452 #endif
453 }
454 
455 void tegra_drm_fb_suspend(struct drm_device *drm)
456 {
457 #ifdef CONFIG_DRM_FBDEV_EMULATION
458 	struct tegra_drm *tegra = drm->dev_private;
459 
460 	console_lock();
461 	drm_fb_helper_set_suspend(&tegra->fbdev->base, 1);
462 	console_unlock();
463 #endif
464 }
465 
466 void tegra_drm_fb_resume(struct drm_device *drm)
467 {
468 #ifdef CONFIG_DRM_FBDEV_EMULATION
469 	struct tegra_drm *tegra = drm->dev_private;
470 
471 	console_lock();
472 	drm_fb_helper_set_suspend(&tegra->fbdev->base, 0);
473 	console_unlock();
474 #endif
475 }
476