2 * drm kms/fb cma (contiguous memory allocator) helper functions
4 * Copyright (C) 2012 Analog Device Inc.
5 * Author: Lars-Peter Clausen <lars@metafoo.de>
8 * Copyright (C) 2012 Red Hat
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
21 #include <drm/drm_crtc.h>
22 #include <drm/drm_fb_helper.h>
23 #include <drm/drm_crtc_helper.h>
24 #include <drm/drm_gem_cma_helper.h>
25 #include <drm/drm_fb_cma_helper.h>
26 #include <linux/module.h>
29 struct drm_framebuffer fb
;
30 struct drm_gem_cma_object
*obj
[4];
33 struct drm_fbdev_cma
{
34 struct drm_fb_helper fb_helper
;
35 struct drm_fb_cma
*fb
;
38 static inline struct drm_fbdev_cma
*to_fbdev_cma(struct drm_fb_helper
*helper
)
40 return container_of(helper
, struct drm_fbdev_cma
, fb_helper
);
43 static inline struct drm_fb_cma
*to_fb_cma(struct drm_framebuffer
*fb
)
45 return container_of(fb
, struct drm_fb_cma
, fb
);
48 static void drm_fb_cma_destroy(struct drm_framebuffer
*fb
)
50 struct drm_fb_cma
*fb_cma
= to_fb_cma(fb
);
53 for (i
= 0; i
< 4; i
++) {
55 drm_gem_object_unreference_unlocked(&fb_cma
->obj
[i
]->base
);
58 drm_framebuffer_cleanup(fb
);
62 static int drm_fb_cma_create_handle(struct drm_framebuffer
*fb
,
63 struct drm_file
*file_priv
, unsigned int *handle
)
65 struct drm_fb_cma
*fb_cma
= to_fb_cma(fb
);
67 return drm_gem_handle_create(file_priv
,
68 &fb_cma
->obj
[0]->base
, handle
);
71 static struct drm_framebuffer_funcs drm_fb_cma_funcs
= {
72 .destroy
= drm_fb_cma_destroy
,
73 .create_handle
= drm_fb_cma_create_handle
,
76 static struct drm_fb_cma
*drm_fb_cma_alloc(struct drm_device
*dev
,
77 struct drm_mode_fb_cmd2
*mode_cmd
, struct drm_gem_cma_object
**obj
,
78 unsigned int num_planes
)
80 struct drm_fb_cma
*fb_cma
;
84 fb_cma
= kzalloc(sizeof(*fb_cma
), GFP_KERNEL
);
86 return ERR_PTR(-ENOMEM
);
88 drm_helper_mode_fill_fb_struct(&fb_cma
->fb
, mode_cmd
);
90 for (i
= 0; i
< num_planes
; i
++)
91 fb_cma
->obj
[i
] = obj
[i
];
93 ret
= drm_framebuffer_init(dev
, &fb_cma
->fb
, &drm_fb_cma_funcs
);
95 dev_err(dev
->dev
, "Failed to initialize framebuffer: %d\n", ret
);
104 * drm_fb_cma_create() - (struct drm_mode_config_funcs *)->fb_create callback function
106 * If your hardware has special alignment or pitch requirements these should be
107 * checked before calling this function.
109 struct drm_framebuffer
*drm_fb_cma_create(struct drm_device
*dev
,
110 struct drm_file
*file_priv
, struct drm_mode_fb_cmd2
*mode_cmd
)
112 struct drm_fb_cma
*fb_cma
;
113 struct drm_gem_cma_object
*objs
[4];
114 struct drm_gem_object
*obj
;
120 hsub
= drm_format_horz_chroma_subsampling(mode_cmd
->pixel_format
);
121 vsub
= drm_format_vert_chroma_subsampling(mode_cmd
->pixel_format
);
123 for (i
= 0; i
< drm_format_num_planes(mode_cmd
->pixel_format
); i
++) {
124 unsigned int width
= mode_cmd
->width
/ (i
? hsub
: 1);
125 unsigned int height
= mode_cmd
->height
/ (i
? vsub
: 1);
126 unsigned int min_size
;
128 obj
= drm_gem_object_lookup(dev
, file_priv
, mode_cmd
->handles
[i
]);
130 dev_err(dev
->dev
, "Failed to lookup GEM object\n");
132 goto err_gem_object_unreference
;
135 min_size
= (height
- 1) * mode_cmd
->pitches
[i
]
136 + width
* drm_format_plane_cpp(mode_cmd
->pixel_format
, i
)
137 + mode_cmd
->offsets
[i
];
139 if (obj
->size
< min_size
) {
140 drm_gem_object_unreference_unlocked(obj
);
142 goto err_gem_object_unreference
;
144 objs
[i
] = to_drm_gem_cma_obj(obj
);
147 fb_cma
= drm_fb_cma_alloc(dev
, mode_cmd
, objs
, i
);
148 if (IS_ERR(fb_cma
)) {
149 ret
= PTR_ERR(fb_cma
);
150 goto err_gem_object_unreference
;
155 err_gem_object_unreference
:
156 for (i
--; i
>= 0; i
--)
157 drm_gem_object_unreference_unlocked(&objs
[i
]->base
);
160 EXPORT_SYMBOL_GPL(drm_fb_cma_create
);
163 * drm_fb_cma_get_gem_obj() - Get CMA GEM object for framebuffer
164 * @fb: The framebuffer
165 * @plane: Which plane
167 * Return the CMA GEM object for given framebuffer.
169 * This function will usually be called from the CRTC callback functions.
171 struct drm_gem_cma_object
*drm_fb_cma_get_gem_obj(struct drm_framebuffer
*fb
,
174 struct drm_fb_cma
*fb_cma
= to_fb_cma(fb
);
179 return fb_cma
->obj
[plane
];
181 EXPORT_SYMBOL_GPL(drm_fb_cma_get_gem_obj
);
183 #ifdef CONFIG_DEBUG_FS
185 * drm_fb_cma_describe() - Helper to dump information about a single
186 * CMA framebuffer object
188 static void drm_fb_cma_describe(struct drm_framebuffer
*fb
, struct seq_file
*m
)
190 struct drm_fb_cma
*fb_cma
= to_fb_cma(fb
);
191 int i
, n
= drm_format_num_planes(fb
->pixel_format
);
193 seq_printf(m
, "fb: %dx%d@%4.4s\n", fb
->width
, fb
->height
,
194 (char *)&fb
->pixel_format
);
196 for (i
= 0; i
< n
; i
++) {
197 seq_printf(m
, " %d: offset=%d pitch=%d, obj: ",
198 i
, fb
->offsets
[i
], fb
->pitches
[i
]);
199 drm_gem_cma_describe(fb_cma
->obj
[i
], m
);
204 * drm_fb_cma_debugfs_show() - Helper to list CMA framebuffer objects
207 int drm_fb_cma_debugfs_show(struct seq_file
*m
, void *arg
)
209 struct drm_info_node
*node
= (struct drm_info_node
*) m
->private;
210 struct drm_device
*dev
= node
->minor
->dev
;
211 struct drm_framebuffer
*fb
;
214 ret
= mutex_lock_interruptible(&dev
->mode_config
.mutex
);
218 ret
= mutex_lock_interruptible(&dev
->struct_mutex
);
220 mutex_unlock(&dev
->mode_config
.mutex
);
224 list_for_each_entry(fb
, &dev
->mode_config
.fb_list
, head
)
225 drm_fb_cma_describe(fb
, m
);
227 mutex_unlock(&dev
->struct_mutex
);
228 mutex_unlock(&dev
->mode_config
.mutex
);
232 EXPORT_SYMBOL_GPL(drm_fb_cma_debugfs_show
);
235 static struct fb_ops drm_fbdev_cma_ops
= {
236 .owner
= THIS_MODULE
,
237 .fb_fillrect
= sys_fillrect
,
238 .fb_copyarea
= sys_copyarea
,
239 .fb_imageblit
= sys_imageblit
,
240 .fb_check_var
= drm_fb_helper_check_var
,
241 .fb_set_par
= drm_fb_helper_set_par
,
242 .fb_blank
= drm_fb_helper_blank
,
243 .fb_pan_display
= drm_fb_helper_pan_display
,
244 .fb_setcmap
= drm_fb_helper_setcmap
,
247 static int drm_fbdev_cma_create(struct drm_fb_helper
*helper
,
248 struct drm_fb_helper_surface_size
*sizes
)
250 struct drm_fbdev_cma
*fbdev_cma
= to_fbdev_cma(helper
);
251 struct drm_mode_fb_cmd2 mode_cmd
= { 0 };
252 struct drm_device
*dev
= helper
->dev
;
253 struct drm_gem_cma_object
*obj
;
254 struct drm_framebuffer
*fb
;
255 unsigned int bytes_per_pixel
;
256 unsigned long offset
;
261 DRM_DEBUG_KMS("surface width(%d), height(%d) and bpp(%d)\n",
262 sizes
->surface_width
, sizes
->surface_height
,
265 bytes_per_pixel
= DIV_ROUND_UP(sizes
->surface_bpp
, 8);
267 mode_cmd
.width
= sizes
->surface_width
;
268 mode_cmd
.height
= sizes
->surface_height
;
269 mode_cmd
.pitches
[0] = sizes
->surface_width
* bytes_per_pixel
;
270 mode_cmd
.pixel_format
= drm_mode_legacy_fb_format(sizes
->surface_bpp
,
271 sizes
->surface_depth
);
273 size
= mode_cmd
.pitches
[0] * mode_cmd
.height
;
274 obj
= drm_gem_cma_create(dev
, size
);
278 fbi
= framebuffer_alloc(0, dev
->dev
);
280 dev_err(dev
->dev
, "Failed to allocate framebuffer info.\n");
282 goto err_drm_gem_cma_free_object
;
285 fbdev_cma
->fb
= drm_fb_cma_alloc(dev
, &mode_cmd
, &obj
, 1);
286 if (IS_ERR(fbdev_cma
->fb
)) {
287 dev_err(dev
->dev
, "Failed to allocate DRM framebuffer.\n");
288 ret
= PTR_ERR(fbdev_cma
->fb
);
289 goto err_framebuffer_release
;
292 fb
= &fbdev_cma
->fb
->fb
;
297 fbi
->flags
= FBINFO_FLAG_DEFAULT
;
298 fbi
->fbops
= &drm_fbdev_cma_ops
;
300 ret
= fb_alloc_cmap(&fbi
->cmap
, 256, 0);
302 dev_err(dev
->dev
, "Failed to allocate color map.\n");
303 goto err_drm_fb_cma_destroy
;
306 drm_fb_helper_fill_fix(fbi
, fb
->pitches
[0], fb
->depth
);
307 drm_fb_helper_fill_var(fbi
, helper
, fb
->width
, fb
->height
);
309 offset
= fbi
->var
.xoffset
* bytes_per_pixel
;
310 offset
+= fbi
->var
.yoffset
* fb
->pitches
[0];
312 dev
->mode_config
.fb_base
= (resource_size_t
)obj
->paddr
;
313 fbi
->screen_base
= obj
->vaddr
+ offset
;
314 fbi
->fix
.smem_start
= (unsigned long)(obj
->paddr
+ offset
);
315 fbi
->screen_size
= size
;
316 fbi
->fix
.smem_len
= size
;
320 err_drm_fb_cma_destroy
:
321 drm_framebuffer_unregister_private(fb
);
322 drm_fb_cma_destroy(fb
);
323 err_framebuffer_release
:
324 framebuffer_release(fbi
);
325 err_drm_gem_cma_free_object
:
326 drm_gem_cma_free_object(&obj
->base
);
330 static const struct drm_fb_helper_funcs drm_fb_cma_helper_funcs
= {
331 .fb_probe
= drm_fbdev_cma_create
,
335 * drm_fbdev_cma_init() - Allocate and initializes a drm_fbdev_cma struct
337 * @preferred_bpp: Preferred bits per pixel for the device
338 * @num_crtc: Number of CRTCs
339 * @max_conn_count: Maximum number of connectors
341 * Returns a newly allocated drm_fbdev_cma struct or a ERR_PTR.
343 struct drm_fbdev_cma
*drm_fbdev_cma_init(struct drm_device
*dev
,
344 unsigned int preferred_bpp
, unsigned int num_crtc
,
345 unsigned int max_conn_count
)
347 struct drm_fbdev_cma
*fbdev_cma
;
348 struct drm_fb_helper
*helper
;
351 fbdev_cma
= kzalloc(sizeof(*fbdev_cma
), GFP_KERNEL
);
353 dev_err(dev
->dev
, "Failed to allocate drm fbdev.\n");
354 return ERR_PTR(-ENOMEM
);
357 helper
= &fbdev_cma
->fb_helper
;
359 drm_fb_helper_prepare(dev
, helper
, &drm_fb_cma_helper_funcs
);
361 ret
= drm_fb_helper_init(dev
, helper
, num_crtc
, max_conn_count
);
363 dev_err(dev
->dev
, "Failed to initialize drm fb helper.\n");
367 ret
= drm_fb_helper_single_add_all_connectors(helper
);
369 dev_err(dev
->dev
, "Failed to add connectors.\n");
370 goto err_drm_fb_helper_fini
;
374 /* disable all the possible outputs/crtcs before entering KMS mode */
375 drm_helper_disable_unused_functions(dev
);
377 ret
= drm_fb_helper_initial_config(helper
, preferred_bpp
);
379 dev_err(dev
->dev
, "Failed to set initial hw configuration.\n");
380 goto err_drm_fb_helper_fini
;
385 err_drm_fb_helper_fini
:
386 drm_fb_helper_fini(helper
);
392 EXPORT_SYMBOL_GPL(drm_fbdev_cma_init
);
395 * drm_fbdev_cma_fini() - Free drm_fbdev_cma struct
396 * @fbdev_cma: The drm_fbdev_cma struct
398 void drm_fbdev_cma_fini(struct drm_fbdev_cma
*fbdev_cma
)
400 if (fbdev_cma
->fb_helper
.fbdev
) {
401 struct fb_info
*info
;
404 info
= fbdev_cma
->fb_helper
.fbdev
;
405 ret
= unregister_framebuffer(info
);
407 DRM_DEBUG_KMS("failed unregister_framebuffer()\n");
410 fb_dealloc_cmap(&info
->cmap
);
412 framebuffer_release(info
);
416 drm_framebuffer_unregister_private(&fbdev_cma
->fb
->fb
);
417 drm_fb_cma_destroy(&fbdev_cma
->fb
->fb
);
420 drm_fb_helper_fini(&fbdev_cma
->fb_helper
);
423 EXPORT_SYMBOL_GPL(drm_fbdev_cma_fini
);
426 * drm_fbdev_cma_restore_mode() - Restores initial framebuffer mode
427 * @fbdev_cma: The drm_fbdev_cma struct, may be NULL
429 * This function is usually called from the DRM drivers lastclose callback.
431 void drm_fbdev_cma_restore_mode(struct drm_fbdev_cma
*fbdev_cma
)
434 drm_fb_helper_restore_fbdev_mode_unlocked(&fbdev_cma
->fb_helper
);
436 EXPORT_SYMBOL_GPL(drm_fbdev_cma_restore_mode
);
439 * drm_fbdev_cma_hotplug_event() - Poll for hotpulug events
440 * @fbdev_cma: The drm_fbdev_cma struct, may be NULL
442 * This function is usually called from the DRM drivers output_poll_changed
445 void drm_fbdev_cma_hotplug_event(struct drm_fbdev_cma
*fbdev_cma
)
448 drm_fb_helper_hotplug_event(&fbdev_cma
->fb_helper
);
450 EXPORT_SYMBOL_GPL(drm_fbdev_cma_hotplug_event
);