radeon_fb.c revision 1.5.20.1 1 /* $NetBSD: radeon_fb.c,v 1.5.20.1 2019/06/10 22:08:26 christos Exp $ */
2
3 /*
4 * Copyright 2007 David Airlie
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
15 * Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
24 *
25 * Authors:
26 * David Airlie
27 */
28 #include <sys/cdefs.h>
29 __KERNEL_RCSID(0, "$NetBSD: radeon_fb.c,v 1.5.20.1 2019/06/10 22:08:26 christos Exp $");
30
31 #include <linux/module.h>
32 #include <linux/slab.h>
33 #include <linux/fb.h>
34
35 #include <drm/drmP.h>
36 #include <drm/drm_crtc.h>
37 #include <drm/drm_crtc_helper.h>
38 #include <drm/radeon_drm.h>
39 #include "radeon.h"
40
41 #include <drm/drm_fb_helper.h>
42
43 #include <linux/vga_switcheroo.h>
44
45 #ifdef __NetBSD__
46 #include "radeondrmkmsfb.h"
47 #endif
48
49 /* object hierarchy -
50 this contains a helper + a radeon fb
51 the helper contains a pointer to radeon framebuffer baseclass.
52 */
53 struct radeon_fbdev {
54 struct drm_fb_helper helper;
55 struct radeon_framebuffer rfb;
56 struct list_head fbdev_list;
57 struct radeon_device *rdev;
58 };
59
60 #ifndef __NetBSD__
61 static struct fb_ops radeonfb_ops = {
62 .owner = THIS_MODULE,
63 .fb_check_var = drm_fb_helper_check_var,
64 .fb_set_par = drm_fb_helper_set_par,
65 .fb_fillrect = drm_fb_helper_cfb_fillrect,
66 .fb_copyarea = drm_fb_helper_cfb_copyarea,
67 .fb_imageblit = drm_fb_helper_cfb_imageblit,
68 .fb_pan_display = drm_fb_helper_pan_display,
69 .fb_blank = drm_fb_helper_blank,
70 .fb_setcmap = drm_fb_helper_setcmap,
71 .fb_debug_enter = drm_fb_helper_debug_enter,
72 .fb_debug_leave = drm_fb_helper_debug_leave,
73 };
74 #endif
75
76
77 int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp, bool tiled)
78 {
79 int aligned = width;
80 int align_large = (ASIC_IS_AVIVO(rdev)) || tiled;
81 int pitch_mask = 0;
82
83 switch (bpp / 8) {
84 case 1:
85 pitch_mask = align_large ? 255 : 127;
86 break;
87 case 2:
88 pitch_mask = align_large ? 127 : 31;
89 break;
90 case 3:
91 case 4:
92 pitch_mask = align_large ? 63 : 15;
93 break;
94 }
95
96 aligned += pitch_mask;
97 aligned &= ~pitch_mask;
98 return aligned;
99 }
100
101 static void radeonfb_destroy_pinned_object(struct drm_gem_object *gobj)
102 {
103 struct radeon_bo *rbo = gem_to_radeon_bo(gobj);
104 int ret;
105
106 ret = radeon_bo_reserve(rbo, false);
107 if (likely(ret == 0)) {
108 radeon_bo_kunmap(rbo);
109 radeon_bo_unpin(rbo);
110 radeon_bo_unreserve(rbo);
111 }
112 drm_gem_object_unreference_unlocked(gobj);
113 }
114
115 static int radeonfb_create_pinned_object(struct radeon_fbdev *rfbdev,
116 struct drm_mode_fb_cmd2 *mode_cmd,
117 struct drm_gem_object **gobj_p)
118 {
119 struct radeon_device *rdev = rfbdev->rdev;
120 struct drm_gem_object *gobj = NULL;
121 struct radeon_bo *rbo = NULL;
122 bool fb_tiled = false; /* useful for testing */
123 u32 tiling_flags = 0;
124 int ret;
125 int aligned_size, size;
126 int height = mode_cmd->height;
127 u32 bpp, depth;
128
129 drm_fb_get_bpp_depth(mode_cmd->pixel_format, &depth, &bpp);
130
131 /* need to align pitch with crtc limits */
132 mode_cmd->pitches[0] = radeon_align_pitch(rdev, mode_cmd->width, bpp,
133 fb_tiled) * ((bpp + 1) / 8);
134
135 if (rdev->family >= CHIP_R600)
136 #ifdef __NetBSD__ /* XXX ALIGN means something else. */
137 height = round_up(mode_cmd->height, 8);
138 #else
139 height = ALIGN(mode_cmd->height, 8);
140 #endif
141 size = mode_cmd->pitches[0] * height;
142 #ifdef __NetBSD__ /* XXX ALIGN means something else. */
143 aligned_size = round_up(size, PAGE_SIZE);
144 #else
145 aligned_size = ALIGN(size, PAGE_SIZE);
146 #endif
147 ret = radeon_gem_object_create(rdev, aligned_size, 0,
148 RADEON_GEM_DOMAIN_VRAM,
149 0, true, &gobj);
150 if (ret) {
151 printk(KERN_ERR "failed to allocate framebuffer (%d)\n",
152 aligned_size);
153 return -ENOMEM;
154 }
155 rbo = gem_to_radeon_bo(gobj);
156
157 if (fb_tiled)
158 tiling_flags = RADEON_TILING_MACRO;
159
160 #ifdef __BIG_ENDIAN
161 switch (bpp) {
162 case 32:
163 tiling_flags |= RADEON_TILING_SWAP_32BIT;
164 break;
165 case 16:
166 tiling_flags |= RADEON_TILING_SWAP_16BIT;
167 default:
168 break;
169 }
170 #endif
171
172 if (tiling_flags) {
173 ret = radeon_bo_set_tiling_flags(rbo,
174 tiling_flags | RADEON_TILING_SURFACE,
175 mode_cmd->pitches[0]);
176 if (ret)
177 dev_err(rdev->dev, "FB failed to set tiling flags\n");
178 }
179
180
181 ret = radeon_bo_reserve(rbo, false);
182 if (unlikely(ret != 0))
183 goto out_unref;
184 /* Only 27 bit offset for legacy CRTC */
185 ret = radeon_bo_pin_restricted(rbo, RADEON_GEM_DOMAIN_VRAM,
186 ASIC_IS_AVIVO(rdev) ? 0 : 1 << 27,
187 NULL);
188 if (ret) {
189 radeon_bo_unreserve(rbo);
190 goto out_unref;
191 }
192 if (fb_tiled)
193 radeon_bo_check_tiling(rbo, 0, 0);
194 ret = radeon_bo_kmap(rbo, NULL);
195 radeon_bo_unreserve(rbo);
196 if (ret) {
197 goto out_unref;
198 }
199
200 *gobj_p = gobj;
201 return 0;
202 out_unref:
203 radeonfb_destroy_pinned_object(gobj);
204 *gobj_p = NULL;
205 return ret;
206 }
207
208 static int radeonfb_create(struct drm_fb_helper *helper,
209 struct drm_fb_helper_surface_size *sizes)
210 {
211 struct radeon_fbdev *rfbdev =
212 container_of(helper, struct radeon_fbdev, helper);
213 struct radeon_device *rdev = rfbdev->rdev;
214 #ifndef __NetBSD__
215 struct fb_info *info;
216 #endif
217 struct drm_framebuffer *fb = NULL;
218 struct drm_mode_fb_cmd2 mode_cmd;
219 struct drm_gem_object *gobj = NULL;
220 struct radeon_bo *rbo = NULL;
221 int ret;
222 #ifndef __NetBSD__
223 unsigned long tmp;
224 #endif
225
226 mode_cmd.width = sizes->surface_width;
227 mode_cmd.height = sizes->surface_height;
228
229 /* avivo can't scanout real 24bpp */
230 if ((sizes->surface_bpp == 24) && ASIC_IS_AVIVO(rdev))
231 sizes->surface_bpp = 32;
232
233 mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
234 sizes->surface_depth);
235
236 ret = radeonfb_create_pinned_object(rfbdev, &mode_cmd, &gobj);
237 if (ret) {
238 DRM_ERROR("failed to create fbcon object %d\n", ret);
239 return ret;
240 }
241
242 rbo = gem_to_radeon_bo(gobj);
243
244 #ifdef __NetBSD__
245 ret = radeon_framebuffer_init(rdev->ddev, &rfbdev->rfb, &mode_cmd, gobj);
246 if (ret) {
247 DRM_ERROR("failed to initialize framebuffer %d\n", ret);
248 goto out_unref;
249 }
250
251 (void)memset(rbo->kptr, 0, radeon_bo_size(rbo));
252
253 {
254 static const struct radeonfb_attach_args zero_rfa;
255 struct radeonfb_attach_args rfa = zero_rfa;
256
257 rfa.rfa_fb_helper = helper;
258 rfa.rfa_fb_sizes = *sizes;
259 rfa.rfa_fb_ptr = rbo->kptr;
260 rfa.rfa_fb_linebytes = mode_cmd.pitches[0];
261
262 helper->fbdev = config_found_ia(rdev->ddev->dev, "radeonfbbus", &rfa,
263 NULL);
264 if (helper->fbdev == NULL) {
265 DRM_ERROR("failed to attach genfb\n");
266 goto out_unref;
267 }
268 }
269 fb = &rfbdev->rfb.base;
270 rfbdev->helper.fb = fb;
271 #else
272 /* okay we have an object now allocate the framebuffer */
273 info = drm_fb_helper_alloc_fbi(helper);
274 if (IS_ERR(info)) {
275 ret = PTR_ERR(info);
276 goto out_unref;
277 }
278
279 info->par = rfbdev;
280
281 ret = radeon_framebuffer_init(rdev->ddev, &rfbdev->rfb, &mode_cmd, gobj);
282 if (ret) {
283 DRM_ERROR("failed to initialize framebuffer %d\n", ret);
284 goto out_destroy_fbi;
285 }
286
287 fb = &rfbdev->rfb.base;
288
289 /* setup helper */
290 rfbdev->helper.fb = fb;
291
292 memset_io(rbo->kptr, 0x0, radeon_bo_size(rbo));
293
294 strcpy(info->fix.id, "radeondrmfb");
295
296 drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
297
298 info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT;
299 info->fbops = &radeonfb_ops;
300
301 tmp = radeon_bo_gpu_offset(rbo) - rdev->mc.vram_start;
302 info->fix.smem_start = rdev->mc.aper_base + tmp;
303 info->fix.smem_len = radeon_bo_size(rbo);
304 info->screen_base = rbo->kptr;
305 info->screen_size = radeon_bo_size(rbo);
306
307 drm_fb_helper_fill_var(info, &rfbdev->helper, sizes->fb_width, sizes->fb_height);
308
309 /* setup aperture base/size for vesafb takeover */
310 info->apertures->ranges[0].base = rdev->ddev->mode_config.fb_base;
311 info->apertures->ranges[0].size = rdev->mc.aper_size;
312
313 /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
314
315 if (info->screen_base == NULL) {
316 ret = -ENOSPC;
317 goto out_destroy_fbi;
318 }
319
320 DRM_INFO("fb mappable at 0x%lX\n", info->fix.smem_start);
321 DRM_INFO("vram apper at 0x%lX\n", (unsigned long)rdev->mc.aper_base);
322 DRM_INFO("size %lu\n", (unsigned long)radeon_bo_size(rbo));
323 DRM_INFO("fb depth is %d\n", fb->depth);
324 DRM_INFO(" pitch is %d\n", fb->pitches[0]);
325
326 vga_switcheroo_client_fb_set(rdev->ddev->pdev, info);
327 #endif
328 return 0;
329
330 #ifndef __NetBSD__
331 out_destroy_fbi:
332 drm_fb_helper_release_fbi(helper);
333 #endif
334 out_unref:
335 if (rbo) {
336
337 }
338 if (fb && ret) {
339 drm_gem_object_unreference(gobj);
340 drm_framebuffer_unregister_private(fb);
341 drm_framebuffer_cleanup(fb);
342 kfree(fb);
343 }
344 return ret;
345 }
346
347 void radeon_fb_output_poll_changed(struct radeon_device *rdev)
348 {
349 drm_fb_helper_hotplug_event(&rdev->mode_info.rfbdev->helper);
350 }
351
352 static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfbdev)
353 {
354 struct radeon_framebuffer *rfb = &rfbdev->rfb;
355 #ifdef __NetBSD__
356 int ret;
357 #endif
358
359 #ifdef __NetBSD__
360 /* XXX errno NetBSD->Linux */
361 ret = -config_detach(rfbdev->helper.fbdev, DETACH_FORCE);
362 if (ret)
363 DRM_ERROR("failed to detach radeonfb: %d\n", ret);
364 rfbdev->helper.fbdev = NULL;
365 #else
366 drm_fb_helper_unregister_fbi(&rfbdev->helper);
367 drm_fb_helper_release_fbi(&rfbdev->helper);
368 #endif
369
370 if (rfb->obj) {
371 radeonfb_destroy_pinned_object(rfb->obj);
372 rfb->obj = NULL;
373 }
374 drm_fb_helper_fini(&rfbdev->helper);
375 drm_framebuffer_unregister_private(&rfb->base);
376 drm_framebuffer_cleanup(&rfb->base);
377
378 return 0;
379 }
380
381 static const struct drm_fb_helper_funcs radeon_fb_helper_funcs = {
382 .gamma_set = radeon_crtc_fb_gamma_set,
383 .gamma_get = radeon_crtc_fb_gamma_get,
384 .fb_probe = radeonfb_create,
385 };
386
387 int radeon_fbdev_init(struct radeon_device *rdev)
388 {
389 struct radeon_fbdev *rfbdev;
390 int bpp_sel = 32;
391 int ret;
392
393 /* select 8 bpp console on RN50 or 16MB cards */
394 if (ASIC_IS_RN50(rdev) || rdev->mc.real_vram_size <= (32*1024*1024))
395 bpp_sel = 8;
396
397 rfbdev = kzalloc(sizeof(struct radeon_fbdev), GFP_KERNEL);
398 if (!rfbdev)
399 return -ENOMEM;
400
401 rfbdev->rdev = rdev;
402 rdev->mode_info.rfbdev = rfbdev;
403
404 drm_fb_helper_prepare(rdev->ddev, &rfbdev->helper,
405 &radeon_fb_helper_funcs);
406
407 ret = drm_fb_helper_init(rdev->ddev, &rfbdev->helper,
408 rdev->num_crtc,
409 RADEONFB_CONN_LIMIT);
410 if (ret)
411 goto free;
412
413 ret = drm_fb_helper_single_add_all_connectors(&rfbdev->helper);
414 if (ret)
415 goto fini;
416
417 /* disable all the possible outputs/crtcs before entering KMS mode */
418 drm_helper_disable_unused_functions(rdev->ddev);
419
420 ret = drm_fb_helper_initial_config(&rfbdev->helper, bpp_sel);
421 if (ret)
422 goto fini;
423
424 return 0;
425
426 fini:
427 drm_fb_helper_fini(&rfbdev->helper);
428 free:
429 kfree(rfbdev);
430 return ret;
431 }
432
433 void radeon_fbdev_fini(struct radeon_device *rdev)
434 {
435 if (!rdev->mode_info.rfbdev)
436 return;
437
438 radeon_fbdev_destroy(rdev->ddev, rdev->mode_info.rfbdev);
439 kfree(rdev->mode_info.rfbdev);
440 rdev->mode_info.rfbdev = NULL;
441 }
442
443 void radeon_fbdev_set_suspend(struct radeon_device *rdev, int state)
444 {
445 #ifndef __NetBSD__ /* XXX radeon fb suspend */
446 fb_set_suspend(rdev->mode_info.rfbdev->helper.fbdev, state);
447 #endif
448 }
449
450 bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj)
451 {
452 if (robj == gem_to_radeon_bo(rdev->mode_info.rfbdev->rfb.obj))
453 return true;
454 return false;
455 }
456
457 void radeon_fb_add_connector(struct radeon_device *rdev, struct drm_connector *connector)
458 {
459 drm_fb_helper_add_one_connector(&rdev->mode_info.rfbdev->helper, connector);
460 }
461
462 void radeon_fb_remove_connector(struct radeon_device *rdev, struct drm_connector *connector)
463 {
464 drm_fb_helper_remove_one_connector(&rdev->mode_info.rfbdev->helper, connector);
465 }
466
467 void radeon_fbdev_restore_mode(struct radeon_device *rdev)
468 {
469 struct radeon_fbdev *rfbdev = rdev->mode_info.rfbdev;
470 struct drm_fb_helper *fb_helper;
471 int ret;
472
473 if (!rfbdev)
474 return;
475
476 fb_helper = &rfbdev->helper;
477
478 ret = drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper);
479 if (ret)
480 DRM_DEBUG("failed to restore crtc mode\n");
481 }
482