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
;
213 mutex_lock(&dev
->mode_config
.fb_lock
);
214 drm_for_each_fb(fb
, dev
)
215 drm_fb_cma_describe(fb
, m
);
216 mutex_unlock(&dev
->mode_config
.fb_lock
);
220 EXPORT_SYMBOL_GPL(drm_fb_cma_debugfs_show
);
223 static struct fb_ops drm_fbdev_cma_ops
= {
224 .owner
= THIS_MODULE
,
225 .fb_fillrect
= drm_fb_helper_sys_fillrect
,
226 .fb_copyarea
= drm_fb_helper_sys_copyarea
,
227 .fb_imageblit
= drm_fb_helper_sys_imageblit
,
228 .fb_check_var
= drm_fb_helper_check_var
,
229 .fb_set_par
= drm_fb_helper_set_par
,
230 .fb_blank
= drm_fb_helper_blank
,
231 .fb_pan_display
= drm_fb_helper_pan_display
,
232 .fb_setcmap
= drm_fb_helper_setcmap
,
235 static int drm_fbdev_cma_create(struct drm_fb_helper
*helper
,
236 struct drm_fb_helper_surface_size
*sizes
)
238 struct drm_fbdev_cma
*fbdev_cma
= to_fbdev_cma(helper
);
239 struct drm_mode_fb_cmd2 mode_cmd
= { 0 };
240 struct drm_device
*dev
= helper
->dev
;
241 struct drm_gem_cma_object
*obj
;
242 struct drm_framebuffer
*fb
;
243 unsigned int bytes_per_pixel
;
244 unsigned long offset
;
249 DRM_DEBUG_KMS("surface width(%d), height(%d) and bpp(%d)\n",
250 sizes
->surface_width
, sizes
->surface_height
,
253 bytes_per_pixel
= DIV_ROUND_UP(sizes
->surface_bpp
, 8);
255 mode_cmd
.width
= sizes
->surface_width
;
256 mode_cmd
.height
= sizes
->surface_height
;
257 mode_cmd
.pitches
[0] = sizes
->surface_width
* bytes_per_pixel
;
258 mode_cmd
.pixel_format
= drm_mode_legacy_fb_format(sizes
->surface_bpp
,
259 sizes
->surface_depth
);
261 size
= mode_cmd
.pitches
[0] * mode_cmd
.height
;
262 obj
= drm_gem_cma_create(dev
, size
);
266 fbi
= drm_fb_helper_alloc_fbi(helper
);
269 goto err_drm_gem_cma_free_object
;
272 fbdev_cma
->fb
= drm_fb_cma_alloc(dev
, &mode_cmd
, &obj
, 1);
273 if (IS_ERR(fbdev_cma
->fb
)) {
274 dev_err(dev
->dev
, "Failed to allocate DRM framebuffer.\n");
275 ret
= PTR_ERR(fbdev_cma
->fb
);
276 goto err_fb_info_destroy
;
279 fb
= &fbdev_cma
->fb
->fb
;
283 fbi
->flags
= FBINFO_FLAG_DEFAULT
;
284 fbi
->fbops
= &drm_fbdev_cma_ops
;
286 drm_fb_helper_fill_fix(fbi
, fb
->pitches
[0], fb
->depth
);
287 drm_fb_helper_fill_var(fbi
, helper
, sizes
->fb_width
, sizes
->fb_height
);
289 offset
= fbi
->var
.xoffset
* bytes_per_pixel
;
290 offset
+= fbi
->var
.yoffset
* fb
->pitches
[0];
292 dev
->mode_config
.fb_base
= (resource_size_t
)obj
->paddr
;
293 fbi
->screen_base
= obj
->vaddr
+ offset
;
294 fbi
->fix
.smem_start
= (unsigned long)(obj
->paddr
+ offset
);
295 fbi
->screen_size
= size
;
296 fbi
->fix
.smem_len
= size
;
301 drm_fb_helper_release_fbi(helper
);
302 err_drm_gem_cma_free_object
:
303 drm_gem_cma_free_object(&obj
->base
);
307 static const struct drm_fb_helper_funcs drm_fb_cma_helper_funcs
= {
308 .fb_probe
= drm_fbdev_cma_create
,
312 * drm_fbdev_cma_init() - Allocate and initializes a drm_fbdev_cma struct
314 * @preferred_bpp: Preferred bits per pixel for the device
315 * @num_crtc: Number of CRTCs
316 * @max_conn_count: Maximum number of connectors
318 * Returns a newly allocated drm_fbdev_cma struct or a ERR_PTR.
320 struct drm_fbdev_cma
*drm_fbdev_cma_init(struct drm_device
*dev
,
321 unsigned int preferred_bpp
, unsigned int num_crtc
,
322 unsigned int max_conn_count
)
324 struct drm_fbdev_cma
*fbdev_cma
;
325 struct drm_fb_helper
*helper
;
328 fbdev_cma
= kzalloc(sizeof(*fbdev_cma
), GFP_KERNEL
);
330 dev_err(dev
->dev
, "Failed to allocate drm fbdev.\n");
331 return ERR_PTR(-ENOMEM
);
334 helper
= &fbdev_cma
->fb_helper
;
336 drm_fb_helper_prepare(dev
, helper
, &drm_fb_cma_helper_funcs
);
338 ret
= drm_fb_helper_init(dev
, helper
, num_crtc
, max_conn_count
);
340 dev_err(dev
->dev
, "Failed to initialize drm fb helper.\n");
344 ret
= drm_fb_helper_single_add_all_connectors(helper
);
346 dev_err(dev
->dev
, "Failed to add connectors.\n");
347 goto err_drm_fb_helper_fini
;
351 /* disable all the possible outputs/crtcs before entering KMS mode */
352 drm_helper_disable_unused_functions(dev
);
354 ret
= drm_fb_helper_initial_config(helper
, preferred_bpp
);
356 dev_err(dev
->dev
, "Failed to set initial hw configuration.\n");
357 goto err_drm_fb_helper_fini
;
362 err_drm_fb_helper_fini
:
363 drm_fb_helper_fini(helper
);
369 EXPORT_SYMBOL_GPL(drm_fbdev_cma_init
);
372 * drm_fbdev_cma_fini() - Free drm_fbdev_cma struct
373 * @fbdev_cma: The drm_fbdev_cma struct
375 void drm_fbdev_cma_fini(struct drm_fbdev_cma
*fbdev_cma
)
377 drm_fb_helper_unregister_fbi(&fbdev_cma
->fb_helper
);
378 drm_fb_helper_release_fbi(&fbdev_cma
->fb_helper
);
381 drm_framebuffer_unregister_private(&fbdev_cma
->fb
->fb
);
382 drm_fb_cma_destroy(&fbdev_cma
->fb
->fb
);
385 drm_fb_helper_fini(&fbdev_cma
->fb_helper
);
388 EXPORT_SYMBOL_GPL(drm_fbdev_cma_fini
);
391 * drm_fbdev_cma_restore_mode() - Restores initial framebuffer mode
392 * @fbdev_cma: The drm_fbdev_cma struct, may be NULL
394 * This function is usually called from the DRM drivers lastclose callback.
396 void drm_fbdev_cma_restore_mode(struct drm_fbdev_cma
*fbdev_cma
)
399 drm_fb_helper_restore_fbdev_mode_unlocked(&fbdev_cma
->fb_helper
);
401 EXPORT_SYMBOL_GPL(drm_fbdev_cma_restore_mode
);
404 * drm_fbdev_cma_hotplug_event() - Poll for hotpulug events
405 * @fbdev_cma: The drm_fbdev_cma struct, may be NULL
407 * This function is usually called from the DRM drivers output_poll_changed
410 void drm_fbdev_cma_hotplug_event(struct drm_fbdev_cma
*fbdev_cma
)
413 drm_fb_helper_hotplug_event(&fbdev_cma
->fb_helper
);
415 EXPORT_SYMBOL_GPL(drm_fbdev_cma_hotplug_event
);