Subversion Repositories Kolibri OS

Rev

Rev 1430 | Rev 1963 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  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.      *  Modularization
  28.      */
  29.  
  30. #include <linux/module.h>
  31. #include <linux/fb.h>
  32.  
  33. #include "drmP.h"
  34. #include "drm.h"
  35. #include "drm_crtc.h"
  36. #include "drm_crtc_helper.h"
  37. #include "radeon_drm.h"
  38. #include "radeon.h"
  39.  
  40. #include "drm_fb_helper.h"
  41.  
  42. #include <drm_mm.h>
  43. #include "radeon_object.h"
  44.  
  45.  
  46. struct fb_info *framebuffer_alloc(size_t size, void *dev);
  47.  
  48. struct radeon_fb_device {
  49.     struct drm_fb_helper        helper;
  50.         struct radeon_framebuffer       *rfb;
  51.         struct radeon_device            *rdev;
  52. };
  53.  
  54. static struct fb_ops radeonfb_ops = {
  55. //   .owner = THIS_MODULE,
  56.         .fb_check_var = drm_fb_helper_check_var,
  57.         .fb_set_par = drm_fb_helper_set_par,
  58.         .fb_setcolreg = drm_fb_helper_setcolreg,
  59. //      .fb_fillrect = cfb_fillrect,
  60. //      .fb_copyarea = cfb_copyarea,
  61. //      .fb_imageblit = cfb_imageblit,
  62. //      .fb_pan_display = drm_fb_helper_pan_display,
  63.         .fb_blank = drm_fb_helper_blank,
  64.         .fb_setcmap = drm_fb_helper_setcmap,
  65. };
  66.  
  67. /**
  68.  * Currently it is assumed that the old framebuffer is reused.
  69.  *
  70.  * LOCKING
  71.  * caller should hold the mode config lock.
  72.  *
  73.  */
  74. int radeonfb_resize(struct drm_device *dev, struct drm_crtc *crtc)
  75. {
  76.         struct fb_info *info;
  77.         struct drm_framebuffer *fb;
  78.         struct drm_display_mode *mode = crtc->desired_mode;
  79.  
  80.         fb = crtc->fb;
  81.         if (fb == NULL) {
  82.                 return 1;
  83.         }
  84.         info = fb->fbdev;
  85.         if (info == NULL) {
  86.                 return 1;
  87.         }
  88.         if (mode == NULL) {
  89.                 return 1;
  90.         }
  91.         info->var.xres = mode->hdisplay;
  92.         info->var.right_margin = mode->hsync_start - mode->hdisplay;
  93.         info->var.hsync_len = mode->hsync_end - mode->hsync_start;
  94.         info->var.left_margin = mode->htotal - mode->hsync_end;
  95.         info->var.yres = mode->vdisplay;
  96.         info->var.lower_margin = mode->vsync_start - mode->vdisplay;
  97.         info->var.vsync_len = mode->vsync_end - mode->vsync_start;
  98.         info->var.upper_margin = mode->vtotal - mode->vsync_end;
  99.         info->var.pixclock = 10000000 / mode->htotal * 1000 / mode->vtotal * 100;
  100.         /* avoid overflow */
  101.         info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh;
  102.  
  103.         return 0;
  104. }
  105. EXPORT_SYMBOL(radeonfb_resize);
  106.  
  107. int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp, bool tiled)
  108. {
  109.         int aligned = width;
  110.         int align_large = (ASIC_IS_AVIVO(rdev)) || tiled;
  111.         int pitch_mask = 0;
  112.  
  113.         switch (bpp / 8) {
  114.         case 1:
  115.                 pitch_mask = align_large ? 255 : 127;
  116.                 break;
  117.         case 2:
  118.                 pitch_mask = align_large ? 127 : 31;
  119.                 break;
  120.         case 3:
  121.         case 4:
  122.                 pitch_mask = align_large ? 63 : 15;
  123.                 break;
  124.         }
  125.  
  126.         aligned += pitch_mask;
  127.         aligned &= ~pitch_mask;
  128.         return aligned;
  129. }
  130.  
  131. static struct drm_fb_helper_funcs radeon_fb_helper_funcs = {
  132.         .gamma_set = radeon_crtc_fb_gamma_set,
  133.         .gamma_get = radeon_crtc_fb_gamma_get,
  134. };
  135.  
  136. int radeonfb_create(struct drm_device *dev,
  137.                     uint32_t fb_width, uint32_t fb_height,
  138.                     uint32_t surface_width, uint32_t surface_height,
  139.                     uint32_t surface_depth, uint32_t surface_bpp,
  140.                     struct drm_framebuffer **fb_p)
  141. {
  142.         struct radeon_device *rdev = dev->dev_private;
  143.         struct fb_info *info;
  144.         struct radeon_fb_device *rfbdev;
  145.         struct drm_framebuffer *fb = NULL;
  146.         struct radeon_framebuffer *rfb;
  147.         struct drm_mode_fb_cmd mode_cmd;
  148.         struct drm_gem_object *gobj = NULL;
  149.         struct radeon_bo *rbo = NULL;
  150.         struct device *device = &rdev->pdev->dev;
  151.         int size, aligned_size, ret;
  152.         u64 fb_gpuaddr;
  153.         void *fbptr = NULL;
  154.         unsigned long tmp;
  155.         bool fb_tiled = false; /* useful for testing */
  156.         u32 tiling_flags = 0;
  157.  
  158.     mode_cmd.width  = surface_width;
  159.         mode_cmd.height = surface_height;
  160.  
  161.         /* avivo can't scanout real 24bpp */
  162.         if ((surface_bpp == 24) && ASIC_IS_AVIVO(rdev))
  163.                 surface_bpp = 32;
  164.  
  165.         mode_cmd.bpp = surface_bpp;
  166.         /* need to align pitch with crtc limits */
  167.         mode_cmd.pitch = radeon_align_pitch(rdev, mode_cmd.width, mode_cmd.bpp, fb_tiled) * ((mode_cmd.bpp + 1) / 8);
  168.         mode_cmd.depth = surface_depth;
  169.  
  170.         size = mode_cmd.pitch * mode_cmd.height;
  171.         aligned_size = ALIGN(size, PAGE_SIZE);
  172.  
  173.         ret = radeon_gem_object_create(rdev, aligned_size, 0,
  174.                         RADEON_GEM_DOMAIN_VRAM,
  175.                         false, ttm_bo_type_kernel,
  176.                         &gobj);
  177.         if (ret) {
  178.                 printk(KERN_ERR "failed to allocate framebuffer (%d %d)\n",
  179.                        surface_width, surface_height);
  180.                 ret = -ENOMEM;
  181.                 goto out;
  182.         }
  183.         rbo = gobj->driver_private;
  184.  
  185.         if (fb_tiled)
  186.                 tiling_flags = RADEON_TILING_MACRO;
  187.  
  188. #ifdef __BIG_ENDIAN
  189.         switch (mode_cmd.bpp) {
  190.         case 32:
  191.                 tiling_flags |= RADEON_TILING_SWAP_32BIT;
  192.                 break;
  193.         case 16:
  194.                 tiling_flags |= RADEON_TILING_SWAP_16BIT;
  195.         default:
  196.                 break;
  197.         }
  198. #endif
  199.  
  200.         if (tiling_flags) {
  201.                 ret = radeon_bo_set_tiling_flags(rbo,
  202.                                         tiling_flags | RADEON_TILING_SURFACE,
  203.                                         mode_cmd.pitch);
  204.                 if (ret)
  205.                         dev_err(rdev->dev, "FB failed to set tiling flags\n");
  206.         }
  207.         mutex_lock(&rdev->ddev->struct_mutex);
  208.         fb = radeon_framebuffer_create(rdev->ddev, &mode_cmd, gobj);
  209.         if (fb == NULL) {
  210.                 DRM_ERROR("failed to allocate fb.\n");
  211.                 ret = -ENOMEM;
  212.                 goto out_unref;
  213.         }
  214.         ret = radeon_bo_reserve(rbo, false);
  215.         if (unlikely(ret != 0))
  216.                 goto out_unref;
  217.         ret = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_gpuaddr);
  218.         if (ret) {
  219.                 radeon_bo_unreserve(rbo);
  220.                 goto out_unref;
  221.         }
  222.         if (fb_tiled)
  223.                 radeon_bo_check_tiling(rbo, 0, 0);
  224.         ret = radeon_bo_kmap(rbo, &fbptr);
  225.         radeon_bo_unreserve(rbo);
  226.         if (ret) {
  227.                 goto out_unref;
  228.         }
  229.  
  230.     list_add(&fb->filp_head, &rdev->ddev->mode_config.fb_kernel_list);
  231.  
  232.         *fb_p = fb;
  233.         rfb = to_radeon_framebuffer(fb);
  234.         rdev->fbdev_rfb = rfb;
  235.         rdev->fbdev_rbo = rbo;
  236.  
  237.         info = framebuffer_alloc(sizeof(struct radeon_fb_device), device);
  238.         if (info == NULL) {
  239.                 ret = -ENOMEM;
  240.                 goto out_unref;
  241.         }
  242.  
  243.         rdev->fbdev_info = info;
  244.         rfbdev = info->par;
  245.         rfbdev->helper.funcs = &radeon_fb_helper_funcs;
  246.         rfbdev->helper.dev = dev;
  247.         ret = drm_fb_helper_init_crtc_count(&rfbdev->helper, rdev->num_crtc,
  248.                                             RADEONFB_CONN_LIMIT);
  249.         if (ret)
  250.                 goto out_unref;
  251.  
  252.    
  253.         strcpy(info->fix.id, "radeondrmfb");
  254.  
  255.         drm_fb_helper_fill_fix(info, fb->pitch, fb->depth);
  256.  
  257.         info->flags = FBINFO_DEFAULT;
  258.         info->fbops = &radeonfb_ops;
  259.  
  260.         tmp = fb_gpuaddr - rdev->mc.vram_start;
  261.         info->fix.smem_start = rdev->mc.aper_base + tmp;
  262.         info->fix.smem_len = size;
  263.         info->screen_base = fbptr;
  264.         info->screen_size = size;
  265.  
  266.         drm_fb_helper_fill_var(info, fb, fb_width, fb_height);
  267.  
  268.         /* setup aperture base/size for vesafb takeover */
  269.         info->aperture_base = rdev->ddev->mode_config.fb_base;
  270.         info->aperture_size = rdev->mc.real_vram_size;
  271.  
  272.         info->fix.mmio_start = 0;
  273.         info->fix.mmio_len = 0;
  274. //   info->pixmap.size = 64*1024;
  275. //   info->pixmap.buf_align = 8;
  276. //   info->pixmap.access_align = 32;
  277. //   info->pixmap.flags = FB_PIXMAP_SYSTEM;
  278. //   info->pixmap.scan_align = 1;
  279.         if (info->screen_base == NULL) {
  280.                 ret = -ENOSPC;
  281.                 goto out_unref;
  282.         }
  283.         DRM_INFO("fb mappable at 0x%lX\n",  info->fix.smem_start);
  284.         DRM_INFO("vram apper at 0x%lX\n",  (unsigned long)rdev->mc.aper_base);
  285.         DRM_INFO("size %lu\n", (unsigned long)size);
  286.         DRM_INFO("fb depth is %d\n", fb->depth);
  287.         DRM_INFO("   pitch is %d\n", fb->pitch);
  288.  
  289.         fb->fbdev = info;
  290.         rfbdev->rfb = rfb;
  291.         rfbdev->rdev = rdev;
  292.  
  293.         mutex_unlock(&rdev->ddev->struct_mutex);
  294.         return 0;
  295.  
  296. out_unref:
  297.         if (rbo) {
  298.                 ret = radeon_bo_reserve(rbo, false);
  299.                 if (likely(ret == 0)) {
  300.                         radeon_bo_kunmap(rbo);
  301.                         radeon_bo_unreserve(rbo);
  302.                 }
  303.         }
  304.         if (fb && ret) {
  305.                 list_del(&fb->filp_head);
  306. //      drm_gem_object_unreference(gobj);
  307. //       drm_framebuffer_cleanup(fb);
  308.                 kfree(fb);
  309.         }
  310. //   drm_gem_object_unreference(gobj);
  311.    mutex_unlock(&rdev->ddev->struct_mutex);
  312. out:
  313.         return ret;
  314. }
  315.  
  316. int radeonfb_probe(struct drm_device *dev)
  317. {
  318.         struct radeon_device *rdev = dev->dev_private;
  319.         int bpp_sel = 32;
  320.  
  321.         /* select 8 bpp console on RN50 or 16MB cards */
  322.         if (ASIC_IS_RN50(rdev) || rdev->mc.real_vram_size <= (32*1024*1024))
  323.                 bpp_sel = 8;
  324.  
  325.         return drm_fb_helper_single_fb_probe(dev, 32, &radeonfb_create);
  326. }
  327.  
  328. int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb)
  329. {
  330.         struct fb_info *info;
  331.         struct radeon_framebuffer *rfb = to_radeon_framebuffer(fb);
  332.         struct radeon_bo *rbo;
  333.         int r;
  334.  
  335.         if (!fb) {
  336.                 return -EINVAL;
  337.         }
  338.         info = fb->fbdev;
  339.         if (info) {
  340.                 struct radeon_fb_device *rfbdev = info->par;
  341.                 rbo = rfb->obj->driver_private;
  342. //       unregister_framebuffer(info);
  343.                 r = radeon_bo_reserve(rbo, false);
  344.                 if (likely(r == 0)) {
  345.                         radeon_bo_kunmap(rbo);
  346.                         radeon_bo_unpin(rbo);
  347.                         radeon_bo_unreserve(rbo);
  348.                 }
  349.                 drm_fb_helper_free(&rfbdev->helper);
  350.                 framebuffer_release(info);
  351.         }
  352.  
  353.         printk(KERN_INFO "unregistered panic notifier\n");
  354.  
  355.         return 0;
  356. }
  357. EXPORT_SYMBOL(radeonfb_remove);
  358. MODULE_LICENSE("GPL");
  359.