2 * Copyright (C) 2012 Russell King
3 * Written from the i915 driver.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 #include <linux/errno.h>
11 #include <linux/kernel.h>
12 #include <linux/module.h>
15 #include <drm/drm_fb_helper.h>
16 #include "armada_crtc.h"
17 #include "armada_drm.h"
18 #include "armada_fb.h"
19 #include "armada_gem.h"
21 static /*const*/ struct fb_ops armada_fb_ops
= {
23 .fb_check_var
= drm_fb_helper_check_var
,
24 .fb_set_par
= drm_fb_helper_set_par
,
25 .fb_fillrect
= cfb_fillrect
,
26 .fb_copyarea
= cfb_copyarea
,
27 .fb_imageblit
= cfb_imageblit
,
28 .fb_pan_display
= drm_fb_helper_pan_display
,
29 .fb_blank
= drm_fb_helper_blank
,
30 .fb_setcmap
= drm_fb_helper_setcmap
,
31 .fb_debug_enter
= drm_fb_helper_debug_enter
,
32 .fb_debug_leave
= drm_fb_helper_debug_leave
,
35 static int armada_fb_create(struct drm_fb_helper
*fbh
,
36 struct drm_fb_helper_surface_size
*sizes
)
38 struct drm_device
*dev
= fbh
->dev
;
39 struct drm_mode_fb_cmd2 mode
;
40 struct armada_framebuffer
*dfb
;
41 struct armada_gem_object
*obj
;
46 memset(&mode
, 0, sizeof(mode
));
47 mode
.width
= sizes
->surface_width
;
48 mode
.height
= sizes
->surface_height
;
49 mode
.pitches
[0] = armada_pitch(mode
.width
, sizes
->surface_bpp
);
50 mode
.pixel_format
= drm_mode_legacy_fb_format(sizes
->surface_bpp
,
51 sizes
->surface_depth
);
53 size
= mode
.pitches
[0] * mode
.height
;
54 obj
= armada_gem_alloc_private_object(dev
, size
);
56 DRM_ERROR("failed to allocate fb memory\n");
60 ret
= armada_gem_linear_back(dev
, obj
);
62 drm_gem_object_unreference_unlocked(&obj
->obj
);
66 ptr
= armada_gem_map_object(dev
, obj
);
68 drm_gem_object_unreference_unlocked(&obj
->obj
);
72 dfb
= armada_framebuffer_create(dev
, &mode
, obj
);
75 * A reference is now held by the framebuffer object if
76 * successful, otherwise this drops the ref for the error path.
78 drm_gem_object_unreference_unlocked(&obj
->obj
);
83 info
= framebuffer_alloc(0, dev
->dev
);
89 ret
= fb_alloc_cmap(&info
->cmap
, 256, 0);
95 strlcpy(info
->fix
.id
, "armada-drmfb", sizeof(info
->fix
.id
));
97 info
->flags
= FBINFO_DEFAULT
| FBINFO_CAN_FORCE_OUTPUT
;
98 info
->fbops
= &armada_fb_ops
;
99 info
->fix
.smem_start
= obj
->phys_addr
;
100 info
->fix
.smem_len
= obj
->obj
.size
;
101 info
->screen_size
= obj
->obj
.size
;
102 info
->screen_base
= ptr
;
105 drm_fb_helper_fill_fix(info
, dfb
->fb
.pitches
[0], dfb
->fb
.depth
);
106 drm_fb_helper_fill_var(info
, fbh
, sizes
->fb_width
, sizes
->fb_height
);
108 DRM_DEBUG_KMS("allocated %dx%d %dbpp fb: 0x%08llx\n",
109 dfb
->fb
.width
, dfb
->fb
.height
, dfb
->fb
.bits_per_pixel
,
110 (unsigned long long)obj
->phys_addr
);
115 framebuffer_release(info
);
117 dfb
->fb
.funcs
->destroy(&dfb
->fb
);
121 static int armada_fb_probe(struct drm_fb_helper
*fbh
,
122 struct drm_fb_helper_surface_size
*sizes
)
127 ret
= armada_fb_create(fbh
, sizes
);
134 static const struct drm_fb_helper_funcs armada_fb_helper_funcs
= {
135 .gamma_set
= armada_drm_crtc_gamma_set
,
136 .gamma_get
= armada_drm_crtc_gamma_get
,
137 .fb_probe
= armada_fb_probe
,
140 int armada_fbdev_init(struct drm_device
*dev
)
142 struct armada_private
*priv
= dev
->dev_private
;
143 struct drm_fb_helper
*fbh
;
146 fbh
= devm_kzalloc(dev
->dev
, sizeof(*fbh
), GFP_KERNEL
);
152 drm_fb_helper_prepare(dev
, fbh
, &armada_fb_helper_funcs
);
154 ret
= drm_fb_helper_init(dev
, fbh
, 1, 1);
156 DRM_ERROR("failed to initialize drm fb helper\n");
160 ret
= drm_fb_helper_single_add_all_connectors(fbh
);
162 DRM_ERROR("failed to add fb connectors\n");
166 ret
= drm_fb_helper_initial_config(fbh
, 32);
168 DRM_ERROR("failed to set initial config\n");
174 drm_fb_helper_fini(fbh
);
180 void armada_fbdev_lastclose(struct drm_device
*dev
)
182 struct armada_private
*priv
= dev
->dev_private
;
185 drm_fb_helper_restore_fbdev_mode_unlocked(priv
->fbdev
);
188 void armada_fbdev_fini(struct drm_device
*dev
)
190 struct armada_private
*priv
= dev
->dev_private
;
191 struct drm_fb_helper
*fbh
= priv
->fbdev
;
194 struct fb_info
*info
= fbh
->fbdev
;
197 unregister_framebuffer(info
);
199 fb_dealloc_cmap(&info
->cmap
);
200 framebuffer_release(info
);
203 drm_fb_helper_fini(fbh
);
206 fbh
->fb
->funcs
->destroy(fbh
->fb
);