]> git.ipfire.org Git - thirdparty/kernel/stable.git/blob - drivers/gpu/drm/bochs/bochs_fbdev.c
drm/amd/display: Check hpd_gpio for NULL before accessing it
[thirdparty/kernel/stable.git] / drivers / gpu / drm / bochs / bochs_fbdev.c
1 /*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 */
7
8 #include "bochs.h"
9 #include <drm/drm_gem_framebuffer_helper.h>
10
11 /* ---------------------------------------------------------------------- */
12
13 static int bochsfb_mmap(struct fb_info *info,
14 struct vm_area_struct *vma)
15 {
16 struct drm_fb_helper *fb_helper = info->par;
17 struct bochs_bo *bo = gem_to_bochs_bo(fb_helper->fb->obj[0]);
18
19 return ttm_fbdev_mmap(vma, &bo->bo);
20 }
21
22 static struct fb_ops bochsfb_ops = {
23 .owner = THIS_MODULE,
24 DRM_FB_HELPER_DEFAULT_OPS,
25 .fb_fillrect = drm_fb_helper_cfb_fillrect,
26 .fb_copyarea = drm_fb_helper_cfb_copyarea,
27 .fb_imageblit = drm_fb_helper_cfb_imageblit,
28 .fb_mmap = bochsfb_mmap,
29 };
30
31 static int bochsfb_create_object(struct bochs_device *bochs,
32 const struct drm_mode_fb_cmd2 *mode_cmd,
33 struct drm_gem_object **gobj_p)
34 {
35 struct drm_device *dev = bochs->dev;
36 struct drm_gem_object *gobj;
37 u32 size;
38 int ret = 0;
39
40 size = mode_cmd->pitches[0] * mode_cmd->height;
41 ret = bochs_gem_create(dev, size, true, &gobj);
42 if (ret)
43 return ret;
44
45 *gobj_p = gobj;
46 return ret;
47 }
48
49 static int bochsfb_create(struct drm_fb_helper *helper,
50 struct drm_fb_helper_surface_size *sizes)
51 {
52 struct bochs_device *bochs =
53 container_of(helper, struct bochs_device, fb.helper);
54 struct fb_info *info;
55 struct drm_framebuffer *fb;
56 struct drm_mode_fb_cmd2 mode_cmd;
57 struct drm_gem_object *gobj = NULL;
58 struct bochs_bo *bo = NULL;
59 int size, ret;
60
61 if (sizes->surface_bpp != 32)
62 return -EINVAL;
63
64 mode_cmd.width = sizes->surface_width;
65 mode_cmd.height = sizes->surface_height;
66 mode_cmd.pitches[0] = sizes->surface_width * 4;
67 mode_cmd.pixel_format = DRM_FORMAT_HOST_XRGB8888;
68 size = mode_cmd.pitches[0] * mode_cmd.height;
69
70 /* alloc, pin & map bo */
71 ret = bochsfb_create_object(bochs, &mode_cmd, &gobj);
72 if (ret) {
73 DRM_ERROR("failed to create fbcon backing object %d\n", ret);
74 return ret;
75 }
76
77 bo = gem_to_bochs_bo(gobj);
78
79 ret = ttm_bo_reserve(&bo->bo, true, false, NULL);
80 if (ret)
81 return ret;
82
83 ret = bochs_bo_pin(bo, TTM_PL_FLAG_VRAM, NULL);
84 if (ret) {
85 DRM_ERROR("failed to pin fbcon\n");
86 ttm_bo_unreserve(&bo->bo);
87 return ret;
88 }
89
90 ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages,
91 &bo->kmap);
92 if (ret) {
93 DRM_ERROR("failed to kmap fbcon\n");
94 ttm_bo_unreserve(&bo->bo);
95 return ret;
96 }
97
98 ttm_bo_unreserve(&bo->bo);
99
100 /* init fb device */
101 info = drm_fb_helper_alloc_fbi(helper);
102 if (IS_ERR(info)) {
103 DRM_ERROR("Failed to allocate fbi: %ld\n", PTR_ERR(info));
104 return PTR_ERR(info);
105 }
106
107 info->par = &bochs->fb.helper;
108
109 fb = drm_gem_fbdev_fb_create(bochs->dev, sizes, 0, gobj, NULL);
110 if (IS_ERR(fb)) {
111 DRM_ERROR("Failed to create framebuffer: %ld\n", PTR_ERR(fb));
112 return PTR_ERR(fb);
113 }
114
115 /* setup helper */
116 bochs->fb.helper.fb = fb;
117
118 strcpy(info->fix.id, "bochsdrmfb");
119
120 info->fbops = &bochsfb_ops;
121
122 drm_fb_helper_fill_fix(info, fb->pitches[0], fb->format->depth);
123 drm_fb_helper_fill_var(info, &bochs->fb.helper, sizes->fb_width,
124 sizes->fb_height);
125
126 info->screen_base = bo->kmap.virtual;
127 info->screen_size = size;
128
129 drm_vma_offset_remove(&bo->bo.bdev->vma_manager, &bo->bo.vma_node);
130 info->fix.smem_start = 0;
131 info->fix.smem_len = size;
132 return 0;
133 }
134
135 static const struct drm_fb_helper_funcs bochs_fb_helper_funcs = {
136 .fb_probe = bochsfb_create,
137 };
138
139 static struct drm_framebuffer *
140 bochs_gem_fb_create(struct drm_device *dev, struct drm_file *file,
141 const struct drm_mode_fb_cmd2 *mode_cmd)
142 {
143 if (mode_cmd->pixel_format != DRM_FORMAT_XRGB8888 &&
144 mode_cmd->pixel_format != DRM_FORMAT_BGRX8888)
145 return ERR_PTR(-EINVAL);
146
147 return drm_gem_fb_create(dev, file, mode_cmd);
148 }
149
150 const struct drm_mode_config_funcs bochs_mode_funcs = {
151 .fb_create = bochs_gem_fb_create,
152 };
153
154 int bochs_fbdev_init(struct bochs_device *bochs)
155 {
156 return drm_fb_helper_fbdev_setup(bochs->dev, &bochs->fb.helper,
157 &bochs_fb_helper_funcs, 32, 1);
158 }
159
160 void bochs_fbdev_fini(struct bochs_device *bochs)
161 {
162 drm_fb_helper_fbdev_teardown(bochs->dev);
163 }