1 /* Hisilicon Hibmc SoC drm driver
3 * Based on the bochs drm driver.
5 * Copyright (c) 2016 Huawei Limited.
8 * Rongrong Zou <zourongrong@huawei.com>
9 * Rongrong Zou <zourongrong@gmail.com>
10 * Jianhua Li <lijianhua@huawei.com>
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
19 #include <drm/drm_crtc.h>
20 #include <drm/drm_fb_helper.h>
21 #include <drm/drm_probe_helper.h>
23 #include "hibmc_drm_drv.h"
25 static int hibmcfb_create_object(
26 struct hibmc_drm_private
*priv
,
27 const struct drm_mode_fb_cmd2
*mode_cmd
,
28 struct drm_gem_object
**gobj_p
)
30 struct drm_gem_object
*gobj
;
31 struct drm_device
*dev
= priv
->dev
;
35 size
= mode_cmd
->pitches
[0] * mode_cmd
->height
;
36 ret
= hibmc_gem_create(dev
, size
, true, &gobj
);
44 static struct fb_ops hibmc_drm_fb_ops
= {
46 .fb_check_var
= drm_fb_helper_check_var
,
47 .fb_set_par
= drm_fb_helper_set_par
,
48 .fb_fillrect
= drm_fb_helper_sys_fillrect
,
49 .fb_copyarea
= drm_fb_helper_sys_copyarea
,
50 .fb_imageblit
= drm_fb_helper_sys_imageblit
,
51 .fb_pan_display
= drm_fb_helper_pan_display
,
52 .fb_blank
= drm_fb_helper_blank
,
53 .fb_setcmap
= drm_fb_helper_setcmap
,
56 static int hibmc_drm_fb_create(struct drm_fb_helper
*helper
,
57 struct drm_fb_helper_surface_size
*sizes
)
59 struct hibmc_fbdev
*hi_fbdev
=
60 container_of(helper
, struct hibmc_fbdev
, helper
);
61 struct hibmc_drm_private
*priv
= helper
->dev
->dev_private
;
63 struct drm_mode_fb_cmd2 mode_cmd
;
64 struct drm_gem_object
*gobj
= NULL
;
68 unsigned int bytes_per_pixel
;
69 struct hibmc_bo
*bo
= NULL
;
71 DRM_DEBUG_DRIVER("surface width(%d), height(%d) and bpp(%d)\n",
72 sizes
->surface_width
, sizes
->surface_height
,
75 bytes_per_pixel
= DIV_ROUND_UP(sizes
->surface_bpp
, 8);
77 mode_cmd
.width
= sizes
->surface_width
;
78 mode_cmd
.height
= sizes
->surface_height
;
79 mode_cmd
.pitches
[0] = mode_cmd
.width
* bytes_per_pixel
;
80 mode_cmd
.pixel_format
= drm_mode_legacy_fb_format(sizes
->surface_bpp
,
81 sizes
->surface_depth
);
83 size
= PAGE_ALIGN(mode_cmd
.pitches
[0] * mode_cmd
.height
);
85 ret
= hibmcfb_create_object(priv
, &mode_cmd
, &gobj
);
87 DRM_ERROR("failed to create fbcon backing object: %d\n", ret
);
91 bo
= gem_to_hibmc_bo(gobj
);
93 ret
= ttm_bo_reserve(&bo
->bo
, true, false, NULL
);
95 DRM_ERROR("failed to reserve ttm_bo: %d\n", ret
);
99 ret
= hibmc_bo_pin(bo
, TTM_PL_FLAG_VRAM
, NULL
);
101 DRM_ERROR("failed to pin fbcon: %d\n", ret
);
102 goto out_unreserve_ttm_bo
;
105 ret
= ttm_bo_kmap(&bo
->bo
, 0, bo
->bo
.num_pages
, &bo
->kmap
);
107 DRM_ERROR("failed to kmap fbcon: %d\n", ret
);
110 ttm_bo_unreserve(&bo
->bo
);
112 info
= drm_fb_helper_alloc_fbi(helper
);
115 DRM_ERROR("failed to allocate fbi: %d\n", ret
);
116 goto out_release_fbi
;
119 info
->par
= hi_fbdev
;
121 hi_fbdev
->fb
= hibmc_framebuffer_init(priv
->dev
, &mode_cmd
, gobj
);
122 if (IS_ERR(hi_fbdev
->fb
)) {
123 ret
= PTR_ERR(hi_fbdev
->fb
);
125 DRM_ERROR("failed to initialize framebuffer: %d\n", ret
);
126 goto out_release_fbi
;
129 priv
->fbdev
->size
= size
;
130 hi_fbdev
->helper
.fb
= &hi_fbdev
->fb
->fb
;
132 strcpy(info
->fix
.id
, "hibmcdrmfb");
134 info
->fbops
= &hibmc_drm_fb_ops
;
136 drm_fb_helper_fill_fix(info
, hi_fbdev
->fb
->fb
.pitches
[0],
137 hi_fbdev
->fb
->fb
.format
->depth
);
138 drm_fb_helper_fill_var(info
, &priv
->fbdev
->helper
, sizes
->fb_width
,
141 info
->screen_base
= bo
->kmap
.virtual;
142 info
->screen_size
= size
;
144 info
->fix
.smem_start
= bo
->bo
.mem
.bus
.offset
+ bo
->bo
.mem
.bus
.base
;
145 info
->fix
.smem_len
= size
;
149 ret1
= ttm_bo_reserve(&bo
->bo
, true, false, NULL
);
151 DRM_ERROR("failed to rsv ttm_bo when release fbi: %d\n", ret1
);
154 ttm_bo_kunmap(&bo
->kmap
);
157 out_unreserve_ttm_bo
:
158 ttm_bo_unreserve(&bo
->bo
);
160 drm_gem_object_put_unlocked(gobj
);
165 static void hibmc_fbdev_destroy(struct hibmc_fbdev
*fbdev
)
167 struct hibmc_framebuffer
*gfb
= fbdev
->fb
;
168 struct drm_fb_helper
*fbh
= &fbdev
->helper
;
170 drm_fb_helper_unregister_fbi(fbh
);
172 drm_fb_helper_fini(fbh
);
175 drm_framebuffer_put(&gfb
->fb
);
178 static const struct drm_fb_helper_funcs hibmc_fbdev_helper_funcs
= {
179 .fb_probe
= hibmc_drm_fb_create
,
182 int hibmc_fbdev_init(struct hibmc_drm_private
*priv
)
185 struct fb_var_screeninfo
*var
;
186 struct fb_fix_screeninfo
*fix
;
187 struct hibmc_fbdev
*hifbdev
;
189 hifbdev
= devm_kzalloc(priv
->dev
->dev
, sizeof(*hifbdev
), GFP_KERNEL
);
191 DRM_ERROR("failed to allocate hibmc_fbdev\n");
195 priv
->fbdev
= hifbdev
;
196 drm_fb_helper_prepare(priv
->dev
, &hifbdev
->helper
,
197 &hibmc_fbdev_helper_funcs
);
199 /* Now just one crtc and one channel */
200 ret
= drm_fb_helper_init(priv
->dev
, &hifbdev
->helper
, 1);
202 DRM_ERROR("failed to initialize fb helper: %d\n", ret
);
206 ret
= drm_fb_helper_single_add_all_connectors(&hifbdev
->helper
);
208 DRM_ERROR("failed to add all connectors: %d\n", ret
);
212 ret
= drm_fb_helper_initial_config(&hifbdev
->helper
, 16);
214 DRM_ERROR("failed to setup initial conn config: %d\n", ret
);
218 var
= &hifbdev
->helper
.fbdev
->var
;
219 fix
= &hifbdev
->helper
.fbdev
->fix
;
221 DRM_DEBUG_DRIVER("Member of info->var is :\n"
228 "bits_per_pixel=%d\n"
229 "...\n", var
->xres
, var
->yres
, var
->xres_virtual
,
230 var
->yres_virtual
, var
->xoffset
, var
->yoffset
,
231 var
->bits_per_pixel
);
232 DRM_DEBUG_DRIVER("Member of info->fix is :\n"
244 "...\n", fix
->smem_start
, fix
->smem_len
, fix
->type
,
245 fix
->type_aux
, fix
->visual
, fix
->xpanstep
,
246 fix
->ypanstep
, fix
->ywrapstep
, fix
->line_length
,
247 fix
->accel
, fix
->capabilities
);
252 drm_fb_helper_fini(&hifbdev
->helper
);
256 void hibmc_fbdev_fini(struct hibmc_drm_private
*priv
)
261 hibmc_fbdev_destroy(priv
->fbdev
);