1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2012 Russell King
4 * Written from the i915 driver.
6 #include <linux/errno.h>
7 #include <linux/kernel.h>
8 #include <linux/module.h>
10 #include <drm/drm_fb_helper.h>
11 #include "armada_crtc.h"
12 #include "armada_drm.h"
13 #include "armada_fb.h"
14 #include "armada_gem.h"
16 static /*const*/ struct fb_ops armada_fb_ops
= {
18 DRM_FB_HELPER_DEFAULT_OPS
,
19 .fb_fillrect
= drm_fb_helper_cfb_fillrect
,
20 .fb_copyarea
= drm_fb_helper_cfb_copyarea
,
21 .fb_imageblit
= drm_fb_helper_cfb_imageblit
,
24 static int armada_fbdev_create(struct drm_fb_helper
*fbh
,
25 struct drm_fb_helper_surface_size
*sizes
)
27 struct drm_device
*dev
= fbh
->dev
;
28 struct drm_mode_fb_cmd2 mode
;
29 struct armada_framebuffer
*dfb
;
30 struct armada_gem_object
*obj
;
35 memset(&mode
, 0, sizeof(mode
));
36 mode
.width
= sizes
->surface_width
;
37 mode
.height
= sizes
->surface_height
;
38 mode
.pitches
[0] = armada_pitch(mode
.width
, sizes
->surface_bpp
);
39 mode
.pixel_format
= drm_mode_legacy_fb_format(sizes
->surface_bpp
,
40 sizes
->surface_depth
);
42 size
= mode
.pitches
[0] * mode
.height
;
43 obj
= armada_gem_alloc_private_object(dev
, size
);
45 DRM_ERROR("failed to allocate fb memory\n");
49 ret
= armada_gem_linear_back(dev
, obj
);
51 drm_gem_object_put_unlocked(&obj
->obj
);
55 ptr
= armada_gem_map_object(dev
, obj
);
57 drm_gem_object_put_unlocked(&obj
->obj
);
61 dfb
= armada_framebuffer_create(dev
, &mode
, obj
);
64 * A reference is now held by the framebuffer object if
65 * successful, otherwise this drops the ref for the error path.
67 drm_gem_object_put_unlocked(&obj
->obj
);
72 info
= drm_fb_helper_alloc_fbi(fbh
);
78 info
->fbops
= &armada_fb_ops
;
79 info
->fix
.smem_start
= obj
->phys_addr
;
80 info
->fix
.smem_len
= obj
->obj
.size
;
81 info
->screen_size
= obj
->obj
.size
;
82 info
->screen_base
= ptr
;
85 drm_fb_helper_fill_info(info
, fbh
, sizes
);
87 DRM_DEBUG_KMS("allocated %dx%d %dbpp fb: 0x%08llx\n",
88 dfb
->fb
.width
, dfb
->fb
.height
, dfb
->fb
.format
->cpp
[0] * 8,
89 (unsigned long long)obj
->phys_addr
);
94 dfb
->fb
.funcs
->destroy(&dfb
->fb
);
98 static int armada_fb_probe(struct drm_fb_helper
*fbh
,
99 struct drm_fb_helper_surface_size
*sizes
)
104 ret
= armada_fbdev_create(fbh
, sizes
);
111 static const struct drm_fb_helper_funcs armada_fb_helper_funcs
= {
112 .fb_probe
= armada_fb_probe
,
115 int armada_fbdev_init(struct drm_device
*dev
)
117 struct armada_private
*priv
= dev
->dev_private
;
118 struct drm_fb_helper
*fbh
;
121 fbh
= devm_kzalloc(dev
->dev
, sizeof(*fbh
), GFP_KERNEL
);
127 drm_fb_helper_prepare(dev
, fbh
, &armada_fb_helper_funcs
);
129 ret
= drm_fb_helper_init(dev
, fbh
, 1);
131 DRM_ERROR("failed to initialize drm fb helper\n");
135 ret
= drm_fb_helper_single_add_all_connectors(fbh
);
137 DRM_ERROR("failed to add fb connectors\n");
141 ret
= drm_fb_helper_initial_config(fbh
, 32);
143 DRM_ERROR("failed to set initial config\n");
149 drm_fb_helper_fini(fbh
);
155 void armada_fbdev_fini(struct drm_device
*dev
)
157 struct armada_private
*priv
= dev
->dev_private
;
158 struct drm_fb_helper
*fbh
= priv
->fbdev
;
161 drm_fb_helper_unregister_fbi(fbh
);
163 drm_fb_helper_fini(fbh
);
166 fbh
->fb
->funcs
->destroy(fbh
->fb
);