Home | History | Annotate | Line # | Download | only in radeon
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