LCOV - code coverage report
Current view: top level - dev/pci/drm/radeon - radeon_fb.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 189 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 14 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13