1b843c749SSergey Zigachev /*
2b843c749SSergey Zigachev * Copyright © 2007 David Airlie
3b843c749SSergey Zigachev *
4b843c749SSergey Zigachev * Permission is hereby granted, free of charge, to any person obtaining a
5b843c749SSergey Zigachev * copy of this software and associated documentation files (the "Software"),
6b843c749SSergey Zigachev * to deal in the Software without restriction, including without limitation
7b843c749SSergey Zigachev * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8b843c749SSergey Zigachev * and/or sell copies of the Software, and to permit persons to whom the
9b843c749SSergey Zigachev * Software is furnished to do so, subject to the following conditions:
10b843c749SSergey Zigachev *
11b843c749SSergey Zigachev * The above copyright notice and this permission notice (including the next
12b843c749SSergey Zigachev * paragraph) shall be included in all copies or substantial portions of the
13b843c749SSergey Zigachev * Software.
14b843c749SSergey Zigachev *
15b843c749SSergey Zigachev * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16b843c749SSergey Zigachev * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17b843c749SSergey Zigachev * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18b843c749SSergey Zigachev * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19b843c749SSergey Zigachev * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20b843c749SSergey Zigachev * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21b843c749SSergey Zigachev * DEALINGS IN THE SOFTWARE.
22b843c749SSergey Zigachev *
23b843c749SSergey Zigachev * Authors:
24b843c749SSergey Zigachev * David Airlie
25b843c749SSergey Zigachev */
26b843c749SSergey Zigachev #include <linux/module.h>
27b843c749SSergey Zigachev #include <linux/slab.h>
28*78973132SSergey Zigachev #include <linux/fb.h>
29b843c749SSergey Zigachev #include <linux/pm_runtime.h>
30b843c749SSergey Zigachev
31b843c749SSergey Zigachev #include <drm/drmP.h>
32b843c749SSergey Zigachev #include <drm/drm_crtc.h>
33b843c749SSergey Zigachev #include <drm/drm_crtc_helper.h>
34b843c749SSergey Zigachev #include <drm/amdgpu_drm.h>
35b843c749SSergey Zigachev #include "amdgpu.h"
36b843c749SSergey Zigachev #include "cikd.h"
37b843c749SSergey Zigachev
38b843c749SSergey Zigachev #include <drm/drm_fb_helper.h>
39b843c749SSergey Zigachev
40b843c749SSergey Zigachev #include <linux/vga_switcheroo.h>
41b843c749SSergey Zigachev
42b843c749SSergey Zigachev #include "amdgpu_display.h"
43b843c749SSergey Zigachev
44b843c749SSergey Zigachev /* object hierarchy -
45b843c749SSergey Zigachev this contains a helper + a amdgpu fb
46b843c749SSergey Zigachev the helper contains a pointer to amdgpu framebuffer baseclass.
47b843c749SSergey Zigachev */
48b843c749SSergey Zigachev
49*78973132SSergey Zigachev #if 0
50b843c749SSergey Zigachev static int
51b843c749SSergey Zigachev amdgpufb_open(struct fb_info *info, int user)
52b843c749SSergey Zigachev {
53b843c749SSergey Zigachev struct amdgpu_fbdev *rfbdev = info->par;
54b843c749SSergey Zigachev struct amdgpu_device *adev = rfbdev->adev;
55b843c749SSergey Zigachev int ret = pm_runtime_get_sync(adev->ddev->dev);
56b843c749SSergey Zigachev if (ret < 0 && ret != -EACCES) {
57b843c749SSergey Zigachev pm_runtime_mark_last_busy(adev->ddev->dev);
58b843c749SSergey Zigachev pm_runtime_put_autosuspend(adev->ddev->dev);
59b843c749SSergey Zigachev return ret;
60b843c749SSergey Zigachev }
61b843c749SSergey Zigachev return 0;
62b843c749SSergey Zigachev }
63b843c749SSergey Zigachev
64b843c749SSergey Zigachev static int
65b843c749SSergey Zigachev amdgpufb_release(struct fb_info *info, int user)
66b843c749SSergey Zigachev {
67b843c749SSergey Zigachev struct amdgpu_fbdev *rfbdev = info->par;
68b843c749SSergey Zigachev struct amdgpu_device *adev = rfbdev->adev;
69b843c749SSergey Zigachev
70b843c749SSergey Zigachev pm_runtime_mark_last_busy(adev->ddev->dev);
71b843c749SSergey Zigachev pm_runtime_put_autosuspend(adev->ddev->dev);
72b843c749SSergey Zigachev return 0;
73b843c749SSergey Zigachev }
74*78973132SSergey Zigachev #endif
75b843c749SSergey Zigachev
76b843c749SSergey Zigachev static struct fb_ops amdgpufb_ops = {
77*78973132SSergey Zigachev #if 0
78b843c749SSergey Zigachev .owner = THIS_MODULE,
79*78973132SSergey Zigachev #endif
80b843c749SSergey Zigachev DRM_FB_HELPER_DEFAULT_OPS,
81*78973132SSergey Zigachev #if 0
82b843c749SSergey Zigachev .fb_open = amdgpufb_open,
83b843c749SSergey Zigachev .fb_release = amdgpufb_release,
84b843c749SSergey Zigachev .fb_fillrect = drm_fb_helper_cfb_fillrect,
85b843c749SSergey Zigachev .fb_copyarea = drm_fb_helper_cfb_copyarea,
86b843c749SSergey Zigachev .fb_imageblit = drm_fb_helper_cfb_imageblit,
87*78973132SSergey Zigachev #endif
88b843c749SSergey Zigachev };
89b843c749SSergey Zigachev
90b843c749SSergey Zigachev
amdgpu_align_pitch(struct amdgpu_device * adev,int width,int cpp,bool tiled)91b843c749SSergey Zigachev int amdgpu_align_pitch(struct amdgpu_device *adev, int width, int cpp, bool tiled)
92b843c749SSergey Zigachev {
93b843c749SSergey Zigachev int aligned = width;
94b843c749SSergey Zigachev int pitch_mask = 0;
95b843c749SSergey Zigachev
96b843c749SSergey Zigachev switch (cpp) {
97b843c749SSergey Zigachev case 1:
98b843c749SSergey Zigachev pitch_mask = 255;
99b843c749SSergey Zigachev break;
100b843c749SSergey Zigachev case 2:
101b843c749SSergey Zigachev pitch_mask = 127;
102b843c749SSergey Zigachev break;
103b843c749SSergey Zigachev case 3:
104b843c749SSergey Zigachev case 4:
105b843c749SSergey Zigachev pitch_mask = 63;
106b843c749SSergey Zigachev break;
107b843c749SSergey Zigachev }
108b843c749SSergey Zigachev
109b843c749SSergey Zigachev aligned += pitch_mask;
110b843c749SSergey Zigachev aligned &= ~pitch_mask;
111b843c749SSergey Zigachev return aligned * cpp;
112b843c749SSergey Zigachev }
113b843c749SSergey Zigachev
amdgpufb_destroy_pinned_object(struct drm_gem_object * gobj)114b843c749SSergey Zigachev static void amdgpufb_destroy_pinned_object(struct drm_gem_object *gobj)
115b843c749SSergey Zigachev {
116b843c749SSergey Zigachev struct amdgpu_bo *abo = gem_to_amdgpu_bo(gobj);
117b843c749SSergey Zigachev int ret;
118b843c749SSergey Zigachev
119b843c749SSergey Zigachev ret = amdgpu_bo_reserve(abo, true);
120b843c749SSergey Zigachev if (likely(ret == 0)) {
121b843c749SSergey Zigachev amdgpu_bo_kunmap(abo);
122b843c749SSergey Zigachev amdgpu_bo_unpin(abo);
123b843c749SSergey Zigachev amdgpu_bo_unreserve(abo);
124b843c749SSergey Zigachev }
125b843c749SSergey Zigachev drm_gem_object_put_unlocked(gobj);
126b843c749SSergey Zigachev }
127b843c749SSergey Zigachev
amdgpufb_create_pinned_object(struct amdgpu_fbdev * rfbdev,struct drm_mode_fb_cmd2 * mode_cmd,struct drm_gem_object ** gobj_p)128b843c749SSergey Zigachev static int amdgpufb_create_pinned_object(struct amdgpu_fbdev *rfbdev,
129b843c749SSergey Zigachev struct drm_mode_fb_cmd2 *mode_cmd,
130b843c749SSergey Zigachev struct drm_gem_object **gobj_p)
131b843c749SSergey Zigachev {
132b843c749SSergey Zigachev struct amdgpu_device *adev = rfbdev->adev;
133b843c749SSergey Zigachev struct drm_gem_object *gobj = NULL;
134b843c749SSergey Zigachev struct amdgpu_bo *abo = NULL;
135b843c749SSergey Zigachev bool fb_tiled = false; /* useful for testing */
136b843c749SSergey Zigachev u32 tiling_flags = 0, domain;
137b843c749SSergey Zigachev int ret;
138b843c749SSergey Zigachev int aligned_size, size;
139b843c749SSergey Zigachev int height = mode_cmd->height;
140b843c749SSergey Zigachev u32 cpp;
141b843c749SSergey Zigachev
142b843c749SSergey Zigachev cpp = drm_format_plane_cpp(mode_cmd->pixel_format, 0);
143b843c749SSergey Zigachev
144b843c749SSergey Zigachev /* need to align pitch with crtc limits */
145b843c749SSergey Zigachev mode_cmd->pitches[0] = amdgpu_align_pitch(adev, mode_cmd->width, cpp,
146b843c749SSergey Zigachev fb_tiled);
147b843c749SSergey Zigachev domain = amdgpu_display_supported_domains(adev);
148b843c749SSergey Zigachev
149b843c749SSergey Zigachev height = ALIGN(mode_cmd->height, 8);
150b843c749SSergey Zigachev size = mode_cmd->pitches[0] * height;
151b843c749SSergey Zigachev aligned_size = ALIGN(size, PAGE_SIZE);
152b843c749SSergey Zigachev ret = amdgpu_gem_object_create(adev, aligned_size, 0, domain,
153b843c749SSergey Zigachev AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED |
154b843c749SSergey Zigachev AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS |
155b843c749SSergey Zigachev AMDGPU_GEM_CREATE_VRAM_CLEARED,
156b843c749SSergey Zigachev ttm_bo_type_kernel, NULL, &gobj);
157b843c749SSergey Zigachev if (ret) {
158b843c749SSergey Zigachev pr_err("failed to allocate framebuffer (%d)\n", aligned_size);
159b843c749SSergey Zigachev return -ENOMEM;
160b843c749SSergey Zigachev }
161b843c749SSergey Zigachev abo = gem_to_amdgpu_bo(gobj);
162b843c749SSergey Zigachev
163b843c749SSergey Zigachev if (fb_tiled)
164b843c749SSergey Zigachev tiling_flags = AMDGPU_TILING_SET(ARRAY_MODE, GRPH_ARRAY_2D_TILED_THIN1);
165b843c749SSergey Zigachev
166b843c749SSergey Zigachev ret = amdgpu_bo_reserve(abo, false);
167b843c749SSergey Zigachev if (unlikely(ret != 0))
168b843c749SSergey Zigachev goto out_unref;
169b843c749SSergey Zigachev
170b843c749SSergey Zigachev if (tiling_flags) {
171b843c749SSergey Zigachev ret = amdgpu_bo_set_tiling_flags(abo,
172b843c749SSergey Zigachev tiling_flags);
173b843c749SSergey Zigachev if (ret)
174b843c749SSergey Zigachev dev_err(adev->dev, "FB failed to set tiling flags\n");
175b843c749SSergey Zigachev }
176b843c749SSergey Zigachev
177b843c749SSergey Zigachev
178b843c749SSergey Zigachev ret = amdgpu_bo_pin(abo, domain);
179b843c749SSergey Zigachev if (ret) {
180b843c749SSergey Zigachev amdgpu_bo_unreserve(abo);
181b843c749SSergey Zigachev goto out_unref;
182b843c749SSergey Zigachev }
183b843c749SSergey Zigachev
184b843c749SSergey Zigachev ret = amdgpu_ttm_alloc_gart(&abo->tbo);
185b843c749SSergey Zigachev if (ret) {
186b843c749SSergey Zigachev amdgpu_bo_unreserve(abo);
187b843c749SSergey Zigachev dev_err(adev->dev, "%p bind failed\n", abo);
188b843c749SSergey Zigachev goto out_unref;
189b843c749SSergey Zigachev }
190b843c749SSergey Zigachev
191b843c749SSergey Zigachev ret = amdgpu_bo_kmap(abo, NULL);
192b843c749SSergey Zigachev amdgpu_bo_unreserve(abo);
193b843c749SSergey Zigachev if (ret) {
194b843c749SSergey Zigachev goto out_unref;
195b843c749SSergey Zigachev }
196b843c749SSergey Zigachev
197b843c749SSergey Zigachev *gobj_p = gobj;
198b843c749SSergey Zigachev return 0;
199b843c749SSergey Zigachev out_unref:
200b843c749SSergey Zigachev amdgpufb_destroy_pinned_object(gobj);
201b843c749SSergey Zigachev *gobj_p = NULL;
202b843c749SSergey Zigachev return ret;
203b843c749SSergey Zigachev }
204b843c749SSergey Zigachev
amdgpufb_create(struct drm_fb_helper * helper,struct drm_fb_helper_surface_size * sizes)205b843c749SSergey Zigachev static int amdgpufb_create(struct drm_fb_helper *helper,
206b843c749SSergey Zigachev struct drm_fb_helper_surface_size *sizes)
207b843c749SSergey Zigachev {
208b843c749SSergey Zigachev struct amdgpu_fbdev *rfbdev = (struct amdgpu_fbdev *)helper;
209b843c749SSergey Zigachev struct amdgpu_device *adev = rfbdev->adev;
210b843c749SSergey Zigachev struct fb_info *info;
211b843c749SSergey Zigachev struct drm_framebuffer *fb = NULL;
212b843c749SSergey Zigachev struct drm_mode_fb_cmd2 mode_cmd;
213b843c749SSergey Zigachev struct drm_gem_object *gobj = NULL;
214b843c749SSergey Zigachev struct amdgpu_bo *abo = NULL;
215b843c749SSergey Zigachev int ret;
216*78973132SSergey Zigachev device_t vga_dev = device_get_parent(adev->dev->bsddev);
217b843c749SSergey Zigachev
218b843c749SSergey Zigachev mode_cmd.width = sizes->surface_width;
219b843c749SSergey Zigachev mode_cmd.height = sizes->surface_height;
220b843c749SSergey Zigachev
221b843c749SSergey Zigachev if (sizes->surface_bpp == 24)
222b843c749SSergey Zigachev sizes->surface_bpp = 32;
223b843c749SSergey Zigachev
224b843c749SSergey Zigachev mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
225b843c749SSergey Zigachev sizes->surface_depth);
226b843c749SSergey Zigachev
227b843c749SSergey Zigachev ret = amdgpufb_create_pinned_object(rfbdev, &mode_cmd, &gobj);
228b843c749SSergey Zigachev if (ret) {
229b843c749SSergey Zigachev DRM_ERROR("failed to create fbcon object %d\n", ret);
230b843c749SSergey Zigachev return ret;
231b843c749SSergey Zigachev }
232b843c749SSergey Zigachev
233b843c749SSergey Zigachev abo = gem_to_amdgpu_bo(gobj);
234b843c749SSergey Zigachev
235b843c749SSergey Zigachev /* okay we have an object now allocate the framebuffer */
236b843c749SSergey Zigachev info = drm_fb_helper_alloc_fbi(helper);
237b843c749SSergey Zigachev if (IS_ERR(info)) {
238b843c749SSergey Zigachev ret = PTR_ERR(info);
239b843c749SSergey Zigachev goto out;
240b843c749SSergey Zigachev }
241b843c749SSergey Zigachev
242b843c749SSergey Zigachev info->par = rfbdev;
243*78973132SSergey Zigachev #if 0
244b843c749SSergey Zigachev info->skip_vt_switch = true;
245*78973132SSergey Zigachev #endif
246b843c749SSergey Zigachev
247b843c749SSergey Zigachev ret = amdgpu_display_framebuffer_init(adev->ddev, &rfbdev->rfb,
248b843c749SSergey Zigachev &mode_cmd, gobj);
249b843c749SSergey Zigachev if (ret) {
250b843c749SSergey Zigachev DRM_ERROR("failed to initialize framebuffer %d\n", ret);
251b843c749SSergey Zigachev goto out;
252b843c749SSergey Zigachev }
253b843c749SSergey Zigachev
254b843c749SSergey Zigachev fb = &rfbdev->rfb.base;
255b843c749SSergey Zigachev
256b843c749SSergey Zigachev /* setup helper */
257b843c749SSergey Zigachev rfbdev->helper.fb = fb;
258b843c749SSergey Zigachev
259*78973132SSergey Zigachev #ifdef __DragonFly__
260*78973132SSergey Zigachev info->width = sizes->fb_width;
261*78973132SSergey Zigachev info->height = sizes->fb_height;
262*78973132SSergey Zigachev info->stride = fb->pitches[0];
263*78973132SSergey Zigachev info->depth = sizes->surface_bpp;
264*78973132SSergey Zigachev info->is_vga_boot_display = vga_pci_is_boot_display(vga_dev);
265*78973132SSergey Zigachev info->fbops = amdgpufb_ops;
266*78973132SSergey Zigachev
267*78973132SSergey Zigachev unsigned long tmp = amdgpu_bo_gpu_offset(abo) - adev->gmc.vram_start;
268*78973132SSergey Zigachev info->vaddr = (vm_offset_t)amdgpu_bo_kptr(abo);
269*78973132SSergey Zigachev info->paddr = adev->gmc.aper_base + tmp;
270*78973132SSergey Zigachev #else
271*78973132SSergey Zigachev
272b843c749SSergey Zigachev strcpy(info->fix.id, "amdgpudrmfb");
273b843c749SSergey Zigachev
274b843c749SSergey Zigachev drm_fb_helper_fill_fix(info, fb->pitches[0], fb->format->depth);
275b843c749SSergey Zigachev
276b843c749SSergey Zigachev info->fbops = &amdgpufb_ops;
277b843c749SSergey Zigachev
278b843c749SSergey Zigachev tmp = amdgpu_bo_gpu_offset(abo) - adev->gmc.vram_start;
279b843c749SSergey Zigachev info->fix.smem_start = adev->gmc.aper_base + tmp;
280b843c749SSergey Zigachev info->fix.smem_len = amdgpu_bo_size(abo);
281b843c749SSergey Zigachev info->screen_base = amdgpu_bo_kptr(abo);
282b843c749SSergey Zigachev info->screen_size = amdgpu_bo_size(abo);
283b843c749SSergey Zigachev
284b843c749SSergey Zigachev drm_fb_helper_fill_var(info, &rfbdev->helper, sizes->fb_width, sizes->fb_height);
285b843c749SSergey Zigachev
286b843c749SSergey Zigachev /* setup aperture base/size for vesafb takeover */
287b843c749SSergey Zigachev info->apertures->ranges[0].base = adev->ddev->mode_config.fb_base;
288b843c749SSergey Zigachev info->apertures->ranges[0].size = adev->gmc.aper_size;
289b843c749SSergey Zigachev
290b843c749SSergey Zigachev /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
291b843c749SSergey Zigachev
292b843c749SSergey Zigachev if (info->screen_base == NULL) {
293b843c749SSergey Zigachev ret = -ENOSPC;
294b843c749SSergey Zigachev goto out;
295b843c749SSergey Zigachev }
296*78973132SSergey Zigachev #endif
297b843c749SSergey Zigachev
298*78973132SSergey Zigachev DRM_INFO("fb mappable at 0x%lX\n", info->paddr);
299b843c749SSergey Zigachev DRM_INFO("vram apper at 0x%lX\n", (unsigned long)adev->gmc.aper_base);
300b843c749SSergey Zigachev DRM_INFO("size %lu\n", (unsigned long)amdgpu_bo_size(abo));
301b843c749SSergey Zigachev DRM_INFO("fb depth is %d\n", fb->format->depth);
302b843c749SSergey Zigachev DRM_INFO(" pitch is %d\n", fb->pitches[0]);
303b843c749SSergey Zigachev
304b843c749SSergey Zigachev vga_switcheroo_client_fb_set(adev->ddev->pdev, info);
305b843c749SSergey Zigachev return 0;
306b843c749SSergey Zigachev
307b843c749SSergey Zigachev out:
308b843c749SSergey Zigachev if (abo) {
309b843c749SSergey Zigachev
310b843c749SSergey Zigachev }
311b843c749SSergey Zigachev if (fb && ret) {
312b843c749SSergey Zigachev drm_gem_object_put_unlocked(gobj);
313b843c749SSergey Zigachev drm_framebuffer_unregister_private(fb);
314b843c749SSergey Zigachev drm_framebuffer_cleanup(fb);
315b843c749SSergey Zigachev kfree(fb);
316b843c749SSergey Zigachev }
317b843c749SSergey Zigachev return ret;
318b843c749SSergey Zigachev }
319b843c749SSergey Zigachev
amdgpu_fbdev_destroy(struct drm_device * dev,struct amdgpu_fbdev * rfbdev)320b843c749SSergey Zigachev static int amdgpu_fbdev_destroy(struct drm_device *dev, struct amdgpu_fbdev *rfbdev)
321b843c749SSergey Zigachev {
322b843c749SSergey Zigachev struct amdgpu_framebuffer *rfb = &rfbdev->rfb;
323b843c749SSergey Zigachev int i;
324b843c749SSergey Zigachev
325b843c749SSergey Zigachev drm_fb_helper_unregister_fbi(&rfbdev->helper);
326b843c749SSergey Zigachev
327b843c749SSergey Zigachev if (rfb->base.obj[0]) {
328b843c749SSergey Zigachev for (i = 0; i < rfb->base.format->num_planes; i++)
329b843c749SSergey Zigachev drm_gem_object_put(rfb->base.obj[0]);
330b843c749SSergey Zigachev amdgpufb_destroy_pinned_object(rfb->base.obj[0]);
331b843c749SSergey Zigachev rfb->base.obj[0] = NULL;
332b843c749SSergey Zigachev drm_framebuffer_unregister_private(&rfb->base);
333b843c749SSergey Zigachev drm_framebuffer_cleanup(&rfb->base);
334b843c749SSergey Zigachev }
335b843c749SSergey Zigachev drm_fb_helper_fini(&rfbdev->helper);
336b843c749SSergey Zigachev
337b843c749SSergey Zigachev return 0;
338b843c749SSergey Zigachev }
339b843c749SSergey Zigachev
340b843c749SSergey Zigachev static const struct drm_fb_helper_funcs amdgpu_fb_helper_funcs = {
341b843c749SSergey Zigachev .fb_probe = amdgpufb_create,
342b843c749SSergey Zigachev };
343b843c749SSergey Zigachev
amdgpu_fbdev_init(struct amdgpu_device * adev)344b843c749SSergey Zigachev int amdgpu_fbdev_init(struct amdgpu_device *adev)
345b843c749SSergey Zigachev {
346b843c749SSergey Zigachev struct amdgpu_fbdev *rfbdev;
347b843c749SSergey Zigachev int bpp_sel = 32;
348b843c749SSergey Zigachev int ret;
349b843c749SSergey Zigachev
350b843c749SSergey Zigachev /* don't init fbdev on hw without DCE */
351b843c749SSergey Zigachev if (!adev->mode_info.mode_config_initialized)
352b843c749SSergey Zigachev return 0;
353b843c749SSergey Zigachev
354b843c749SSergey Zigachev /* don't init fbdev if there are no connectors */
355b843c749SSergey Zigachev if (list_empty(&adev->ddev->mode_config.connector_list))
356b843c749SSergey Zigachev return 0;
357b843c749SSergey Zigachev
358b843c749SSergey Zigachev /* select 8 bpp console on low vram cards */
359b843c749SSergey Zigachev if (adev->gmc.real_vram_size <= (32*1024*1024))
360b843c749SSergey Zigachev bpp_sel = 8;
361b843c749SSergey Zigachev
362b843c749SSergey Zigachev rfbdev = kzalloc(sizeof(struct amdgpu_fbdev), GFP_KERNEL);
363b843c749SSergey Zigachev if (!rfbdev)
364b843c749SSergey Zigachev return -ENOMEM;
365b843c749SSergey Zigachev
366b843c749SSergey Zigachev rfbdev->adev = adev;
367b843c749SSergey Zigachev adev->mode_info.rfbdev = rfbdev;
368b843c749SSergey Zigachev
369b843c749SSergey Zigachev drm_fb_helper_prepare(adev->ddev, &rfbdev->helper,
370b843c749SSergey Zigachev &amdgpu_fb_helper_funcs);
371b843c749SSergey Zigachev
372b843c749SSergey Zigachev ret = drm_fb_helper_init(adev->ddev, &rfbdev->helper,
373b843c749SSergey Zigachev AMDGPUFB_CONN_LIMIT);
374b843c749SSergey Zigachev if (ret) {
375b843c749SSergey Zigachev kfree(rfbdev);
376b843c749SSergey Zigachev return ret;
377b843c749SSergey Zigachev }
378b843c749SSergey Zigachev
379b843c749SSergey Zigachev drm_fb_helper_single_add_all_connectors(&rfbdev->helper);
380b843c749SSergey Zigachev
381b843c749SSergey Zigachev /* disable all the possible outputs/crtcs before entering KMS mode */
382b843c749SSergey Zigachev if (!amdgpu_device_has_dc_support(adev))
383b843c749SSergey Zigachev drm_helper_disable_unused_functions(adev->ddev);
384b843c749SSergey Zigachev
385b843c749SSergey Zigachev drm_fb_helper_initial_config(&rfbdev->helper, bpp_sel);
386b843c749SSergey Zigachev return 0;
387b843c749SSergey Zigachev }
388b843c749SSergey Zigachev
amdgpu_fbdev_fini(struct amdgpu_device * adev)389b843c749SSergey Zigachev void amdgpu_fbdev_fini(struct amdgpu_device *adev)
390b843c749SSergey Zigachev {
391b843c749SSergey Zigachev if (!adev->mode_info.rfbdev)
392b843c749SSergey Zigachev return;
393b843c749SSergey Zigachev
394b843c749SSergey Zigachev amdgpu_fbdev_destroy(adev->ddev, adev->mode_info.rfbdev);
395b843c749SSergey Zigachev kfree(adev->mode_info.rfbdev);
396b843c749SSergey Zigachev adev->mode_info.rfbdev = NULL;
397b843c749SSergey Zigachev }
398b843c749SSergey Zigachev
amdgpu_fbdev_set_suspend(struct amdgpu_device * adev,int state)399b843c749SSergey Zigachev void amdgpu_fbdev_set_suspend(struct amdgpu_device *adev, int state)
400b843c749SSergey Zigachev {
401*78973132SSergey Zigachev #if 0
402b843c749SSergey Zigachev if (adev->mode_info.rfbdev)
403b843c749SSergey Zigachev drm_fb_helper_set_suspend_unlocked(&adev->mode_info.rfbdev->helper,
404b843c749SSergey Zigachev state);
405*78973132SSergey Zigachev #endif
406b843c749SSergey Zigachev }
407b843c749SSergey Zigachev
amdgpu_fbdev_total_size(struct amdgpu_device * adev)408b843c749SSergey Zigachev int amdgpu_fbdev_total_size(struct amdgpu_device *adev)
409b843c749SSergey Zigachev {
410b843c749SSergey Zigachev struct amdgpu_bo *robj;
411b843c749SSergey Zigachev int size = 0;
412b843c749SSergey Zigachev
413b843c749SSergey Zigachev if (!adev->mode_info.rfbdev)
414b843c749SSergey Zigachev return 0;
415b843c749SSergey Zigachev
416b843c749SSergey Zigachev robj = gem_to_amdgpu_bo(adev->mode_info.rfbdev->rfb.base.obj[0]);
417b843c749SSergey Zigachev size += amdgpu_bo_size(robj);
418b843c749SSergey Zigachev return size;
419b843c749SSergey Zigachev }
420b843c749SSergey Zigachev
amdgpu_fbdev_robj_is_fb(struct amdgpu_device * adev,struct amdgpu_bo * robj)421b843c749SSergey Zigachev bool amdgpu_fbdev_robj_is_fb(struct amdgpu_device *adev, struct amdgpu_bo *robj)
422b843c749SSergey Zigachev {
423b843c749SSergey Zigachev if (!adev->mode_info.rfbdev)
424b843c749SSergey Zigachev return false;
425b843c749SSergey Zigachev if (robj == gem_to_amdgpu_bo(adev->mode_info.rfbdev->rfb.base.obj[0]))
426b843c749SSergey Zigachev return true;
427b843c749SSergey Zigachev return false;
428b843c749SSergey Zigachev }
429