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 const struct drm_mode_fb_cmd2
*mode_cmd
,
78 struct drm_gem_cma_object
**obj
,
79 unsigned int num_planes
)
81 struct drm_fb_cma
*fb_cma
;
85 fb_cma
= kzalloc(sizeof(*fb_cma
), GFP_KERNEL
);
87 return ERR_PTR(-ENOMEM
);
89 drm_helper_mode_fill_fb_struct(&fb_cma
->fb
, mode_cmd
);
91 for (i
= 0; i
< num_planes
; i
++)
92 fb_cma
->obj
[i
] = obj
[i
];
94 ret
= drm_framebuffer_init(dev
, &fb_cma
->fb
, &drm_fb_cma_funcs
);
96 dev_err(dev
->dev
, "Failed to initialize framebuffer: %d\n", ret
);
105 * drm_fb_cma_create() - (struct drm_mode_config_funcs *)->fb_create callback function
107 * If your hardware has special alignment or pitch requirements these should be
108 * checked before calling this function.
110 struct drm_framebuffer
*drm_fb_cma_create(struct drm_device
*dev
,
111 struct drm_file
*file_priv
, const struct drm_mode_fb_cmd2
*mode_cmd
)
113 struct drm_fb_cma
*fb_cma
;
114 struct drm_gem_cma_object
*objs
[4];
115 struct drm_gem_object
*obj
;
121 hsub
= drm_format_horz_chroma_subsampling(mode_cmd
->pixel_format
);
122 vsub
= drm_format_vert_chroma_subsampling(mode_cmd
->pixel_format
);
124 for (i
= 0; i
< drm_format_num_planes(mode_cmd
->pixel_format
); i
++) {
125 unsigned int width
= mode_cmd
->width
/ (i
? hsub
: 1);
126 unsigned int height
= mode_cmd
->height
/ (i
? vsub
: 1);
127 unsigned int min_size
;
129 obj
= drm_gem_object_lookup(dev
, file_priv
, mode_cmd
->handles
[i
]);
131 dev_err(dev
->dev
, "Failed to lookup GEM object\n");
133 goto err_gem_object_unreference
;
136 min_size
= (height
- 1) * mode_cmd
->pitches
[i
]
137 + width
* drm_format_plane_cpp(mode_cmd
->pixel_format
, i
)
138 + mode_cmd
->offsets
[i
];
140 if (obj
->size
< min_size
) {
141 drm_gem_object_unreference_unlocked(obj
);
143 goto err_gem_object_unreference
;
145 objs
[i
] = to_drm_gem_cma_obj(obj
);
148 fb_cma
= drm_fb_cma_alloc(dev
, mode_cmd
, objs
, i
);
149 if (IS_ERR(fb_cma
)) {
150 ret
= PTR_ERR(fb_cma
);
151 goto err_gem_object_unreference
;
156 err_gem_object_unreference
:
157 for (i
--; i
>= 0; i
--)
158 drm_gem_object_unreference_unlocked(&objs
[i
]->base
);
161 EXPORT_SYMBOL_GPL(drm_fb_cma_create
);
164 * drm_fb_cma_get_gem_obj() - Get CMA GEM object for framebuffer
165 * @fb: The framebuffer
166 * @plane: Which plane
168 * Return the CMA GEM object for given framebuffer.
170 * This function will usually be called from the CRTC callback functions.
172 struct drm_gem_cma_object
*drm_fb_cma_get_gem_obj(struct drm_framebuffer
*fb
,
175 struct drm_fb_cma
*fb_cma
= to_fb_cma(fb
);
180 return fb_cma
->obj
[plane
];
182 EXPORT_SYMBOL_GPL(drm_fb_cma_get_gem_obj
);
184 #ifdef CONFIG_DEBUG_FS
186 * drm_fb_cma_describe() - Helper to dump information about a single
187 * CMA framebuffer object
189 static void drm_fb_cma_describe(struct drm_framebuffer
*fb
, struct seq_file
*m
)
191 struct drm_fb_cma
*fb_cma
= to_fb_cma(fb
);
192 int i
, n
= drm_format_num_planes(fb
->pixel_format
);
194 seq_printf(m
, "fb: %dx%d@%4.4s\n", fb
->width
, fb
->height
,
195 (char *)&fb
->pixel_format
);
197 for (i
= 0; i
< n
; i
++) {
198 seq_printf(m
, " %d: offset=%d pitch=%d, obj: ",
199 i
, fb
->offsets
[i
], fb
->pitches
[i
]);
200 drm_gem_cma_describe(fb_cma
->obj
[i
], m
);
205 * drm_fb_cma_debugfs_show() - Helper to list CMA framebuffer objects
208 int drm_fb_cma_debugfs_show(struct seq_file
*m
, void *arg
)
210 struct drm_info_node
*node
= (struct drm_info_node
*) m
->private;
211 struct drm_device
*dev
= node
->minor
->dev
;
212 struct drm_framebuffer
*fb
;
214 mutex_lock(&dev
->mode_config
.fb_lock
);
215 drm_for_each_fb(fb
, dev
)
216 drm_fb_cma_describe(fb
, m
);
217 mutex_unlock(&dev
->mode_config
.fb_lock
);
221 EXPORT_SYMBOL_GPL(drm_fb_cma_debugfs_show
);
224 static struct fb_ops drm_fbdev_cma_ops
= {
225 .owner
= THIS_MODULE
,
226 .fb_fillrect
= drm_fb_helper_sys_fillrect
,
227 .fb_copyarea
= drm_fb_helper_sys_copyarea
,
228 .fb_imageblit
= drm_fb_helper_sys_imageblit
,
229 .fb_check_var
= drm_fb_helper_check_var
,
230 .fb_set_par
= drm_fb_helper_set_par
,
231 .fb_blank
= drm_fb_helper_blank
,
232 .fb_pan_display
= drm_fb_helper_pan_display
,
233 .fb_setcmap
= drm_fb_helper_setcmap
,
236 static int drm_fbdev_cma_create(struct drm_fb_helper
*helper
,
237 struct drm_fb_helper_surface_size
*sizes
)
239 struct drm_fbdev_cma
*fbdev_cma
= to_fbdev_cma(helper
);
240 struct drm_mode_fb_cmd2 mode_cmd
= { 0 };
241 struct drm_device
*dev
= helper
->dev
;
242 struct drm_gem_cma_object
*obj
;
243 struct drm_framebuffer
*fb
;
244 unsigned int bytes_per_pixel
;
245 unsigned long offset
;
250 DRM_DEBUG_KMS("surface width(%d), height(%d) and bpp(%d)\n",
251 sizes
->surface_width
, sizes
->surface_height
,
254 bytes_per_pixel
= DIV_ROUND_UP(sizes
->surface_bpp
, 8);
256 mode_cmd
.width
= sizes
->surface_width
;
257 mode_cmd
.height
= sizes
->surface_height
;
258 mode_cmd
.pitches
[0] = sizes
->surface_width
* bytes_per_pixel
;
259 mode_cmd
.pixel_format
= drm_mode_legacy_fb_format(sizes
->surface_bpp
,
260 sizes
->surface_depth
);
262 size
= mode_cmd
.pitches
[0] * mode_cmd
.height
;
263 obj
= drm_gem_cma_create(dev
, size
);
267 fbi
= drm_fb_helper_alloc_fbi(helper
);
270 goto err_gem_free_object
;
273 fbdev_cma
->fb
= drm_fb_cma_alloc(dev
, &mode_cmd
, &obj
, 1);
274 if (IS_ERR(fbdev_cma
->fb
)) {
275 dev_err(dev
->dev
, "Failed to allocate DRM framebuffer.\n");
276 ret
= PTR_ERR(fbdev_cma
->fb
);
277 goto err_fb_info_destroy
;
280 fb
= &fbdev_cma
->fb
->fb
;
284 fbi
->flags
= FBINFO_FLAG_DEFAULT
;
285 fbi
->fbops
= &drm_fbdev_cma_ops
;
287 drm_fb_helper_fill_fix(fbi
, fb
->pitches
[0], fb
->depth
);
288 drm_fb_helper_fill_var(fbi
, helper
, sizes
->fb_width
, sizes
->fb_height
);
290 offset
= fbi
->var
.xoffset
* bytes_per_pixel
;
291 offset
+= fbi
->var
.yoffset
* fb
->pitches
[0];
293 dev
->mode_config
.fb_base
= (resource_size_t
)obj
->paddr
;
294 fbi
->screen_base
= obj
->vaddr
+ offset
;
295 fbi
->fix
.smem_start
= (unsigned long)(obj
->paddr
+ offset
);
296 fbi
->screen_size
= size
;
297 fbi
->fix
.smem_len
= size
;
302 drm_fb_helper_release_fbi(helper
);
304 dev
->driver
->gem_free_object(&obj
->base
);
308 static const struct drm_fb_helper_funcs drm_fb_cma_helper_funcs
= {
309 .fb_probe
= drm_fbdev_cma_create
,
313 * drm_fbdev_cma_init() - Allocate and initializes a drm_fbdev_cma struct
315 * @preferred_bpp: Preferred bits per pixel for the device
316 * @num_crtc: Number of CRTCs
317 * @max_conn_count: Maximum number of connectors
319 * Returns a newly allocated drm_fbdev_cma struct or a ERR_PTR.
321 struct drm_fbdev_cma
*drm_fbdev_cma_init(struct drm_device
*dev
,
322 unsigned int preferred_bpp
, unsigned int num_crtc
,
323 unsigned int max_conn_count
)
325 struct drm_fbdev_cma
*fbdev_cma
;
326 struct drm_fb_helper
*helper
;
329 fbdev_cma
= kzalloc(sizeof(*fbdev_cma
), GFP_KERNEL
);
331 dev_err(dev
->dev
, "Failed to allocate drm fbdev.\n");
332 return ERR_PTR(-ENOMEM
);
335 helper
= &fbdev_cma
->fb_helper
;
337 drm_fb_helper_prepare(dev
, helper
, &drm_fb_cma_helper_funcs
);
339 ret
= drm_fb_helper_init(dev
, helper
, num_crtc
, max_conn_count
);
341 dev_err(dev
->dev
, "Failed to initialize drm fb helper.\n");
345 ret
= drm_fb_helper_single_add_all_connectors(helper
);
347 dev_err(dev
->dev
, "Failed to add connectors.\n");
348 goto err_drm_fb_helper_fini
;
352 ret
= drm_fb_helper_initial_config(helper
, preferred_bpp
);
354 dev_err(dev
->dev
, "Failed to set initial hw configuration.\n");
355 goto err_drm_fb_helper_fini
;
360 err_drm_fb_helper_fini
:
361 drm_fb_helper_fini(helper
);
367 EXPORT_SYMBOL_GPL(drm_fbdev_cma_init
);
370 * drm_fbdev_cma_fini() - Free drm_fbdev_cma struct
371 * @fbdev_cma: The drm_fbdev_cma struct
373 void drm_fbdev_cma_fini(struct drm_fbdev_cma
*fbdev_cma
)
375 drm_fb_helper_unregister_fbi(&fbdev_cma
->fb_helper
);
376 drm_fb_helper_release_fbi(&fbdev_cma
->fb_helper
);
379 drm_framebuffer_unregister_private(&fbdev_cma
->fb
->fb
);
380 drm_fb_cma_destroy(&fbdev_cma
->fb
->fb
);
383 drm_fb_helper_fini(&fbdev_cma
->fb_helper
);
386 EXPORT_SYMBOL_GPL(drm_fbdev_cma_fini
);
389 * drm_fbdev_cma_restore_mode() - Restores initial framebuffer mode
390 * @fbdev_cma: The drm_fbdev_cma struct, may be NULL
392 * This function is usually called from the DRM drivers lastclose callback.
394 void drm_fbdev_cma_restore_mode(struct drm_fbdev_cma
*fbdev_cma
)
397 drm_fb_helper_restore_fbdev_mode_unlocked(&fbdev_cma
->fb_helper
);
399 EXPORT_SYMBOL_GPL(drm_fbdev_cma_restore_mode
);
402 * drm_fbdev_cma_hotplug_event() - Poll for hotpulug events
403 * @fbdev_cma: The drm_fbdev_cma struct, may be NULL
405 * This function is usually called from the DRM drivers output_poll_changed
408 void drm_fbdev_cma_hotplug_event(struct drm_fbdev_cma
*fbdev_cma
)
411 drm_fb_helper_hotplug_event(&fbdev_cma
->fb_helper
);
413 EXPORT_SYMBOL_GPL(drm_fbdev_cma_hotplug_event
);