linux/drivers/gpu/drm/gma500/accel_2d.c
<<
>>
Prefs
   1/**************************************************************************
   2 * Copyright (c) 2007-2011, Intel Corporation.
   3 * All Rights Reserved.
   4 *
   5 * This program is free software; you can redistribute it and/or modify it
   6 * under the terms and conditions of the GNU General Public License,
   7 * version 2, as published by the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope it will be useful, but WITHOUT
  10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  12 * more details.
  13 *
  14 * You should have received a copy of the GNU General Public License along with
  15 * this program; if not, write to the Free Software Foundation, Inc.,
  16 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
  17 *
  18 * Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
  19 * develop this driver.
  20 *
  21 **************************************************************************/
  22
  23#include <linux/module.h>
  24#include <linux/kernel.h>
  25#include <linux/errno.h>
  26#include <linux/string.h>
  27#include <linux/mm.h>
  28#include <linux/tty.h>
  29#include <linux/slab.h>
  30#include <linux/delay.h>
  31#include <linux/init.h>
  32#include <linux/console.h>
  33
  34#include <drm/drmP.h>
  35#include <drm/drm.h>
  36#include <drm/drm_crtc.h>
  37
  38#include "psb_drv.h"
  39#include "psb_reg.h"
  40#include "framebuffer.h"
  41
  42/**
  43 *      psb_spank               -       reset the 2D engine
  44 *      @dev_priv: our PSB DRM device
  45 *
  46 *      Soft reset the graphics engine and then reload the necessary registers.
  47 *      We use this at initialisation time but it will become relevant for
  48 *      accelerated X later
  49 */
  50void psb_spank(struct drm_psb_private *dev_priv)
  51{
  52        PSB_WSGX32(_PSB_CS_RESET_BIF_RESET | _PSB_CS_RESET_DPM_RESET |
  53                _PSB_CS_RESET_TA_RESET | _PSB_CS_RESET_USE_RESET |
  54                _PSB_CS_RESET_ISP_RESET | _PSB_CS_RESET_TSP_RESET |
  55                _PSB_CS_RESET_TWOD_RESET, PSB_CR_SOFT_RESET);
  56        PSB_RSGX32(PSB_CR_SOFT_RESET);
  57
  58        msleep(1);
  59
  60        PSB_WSGX32(0, PSB_CR_SOFT_RESET);
  61        wmb();
  62        PSB_WSGX32(PSB_RSGX32(PSB_CR_BIF_CTRL) | _PSB_CB_CTRL_CLEAR_FAULT,
  63                   PSB_CR_BIF_CTRL);
  64        wmb();
  65        (void) PSB_RSGX32(PSB_CR_BIF_CTRL);
  66
  67        msleep(1);
  68        PSB_WSGX32(PSB_RSGX32(PSB_CR_BIF_CTRL) & ~_PSB_CB_CTRL_CLEAR_FAULT,
  69                   PSB_CR_BIF_CTRL);
  70        (void) PSB_RSGX32(PSB_CR_BIF_CTRL);
  71        PSB_WSGX32(dev_priv->gtt.gatt_start, PSB_CR_BIF_TWOD_REQ_BASE);
  72}
  73
  74/**
  75 *      psb2_2d_wait_available  -       wait for FIFO room
  76 *      @dev_priv: our DRM device
  77 *      @size: size (in dwords) of the command we want to issue
  78 *
  79 *      Wait until there is room to load the FIFO with our data. If the
  80 *      device is not responding then reset it
  81 */
  82static int psb_2d_wait_available(struct drm_psb_private *dev_priv,
  83                          unsigned size)
  84{
  85        uint32_t avail = PSB_RSGX32(PSB_CR_2D_SOCIF);
  86        unsigned long t = jiffies + HZ;
  87
  88        while (avail < size) {
  89                avail = PSB_RSGX32(PSB_CR_2D_SOCIF);
  90                if (time_after(jiffies, t)) {
  91                        psb_spank(dev_priv);
  92                        return -EIO;
  93                }
  94        }
  95        return 0;
  96}
  97
  98/**
  99 *      psb_2d_submit           -       submit a 2D command
 100 *      @dev_priv: our DRM device
 101 *      @cmdbuf: command to issue
 102 *      @size: length (in dwords)
 103 *
 104 *      Issue one or more 2D commands to the accelerator. This needs to be
 105 *      serialized later when we add the GEM interfaces for acceleration
 106 */
 107static int psbfb_2d_submit(struct drm_psb_private *dev_priv, uint32_t *cmdbuf,
 108                                                                unsigned size)
 109{
 110        int ret = 0;
 111        int i;
 112        unsigned submit_size;
 113        unsigned long flags;
 114
 115        spin_lock_irqsave(&dev_priv->lock_2d, flags);
 116        while (size > 0) {
 117                submit_size = (size < 0x60) ? size : 0x60;
 118                size -= submit_size;
 119                ret = psb_2d_wait_available(dev_priv, submit_size);
 120                if (ret)
 121                        break;
 122
 123                submit_size <<= 2;
 124
 125                for (i = 0; i < submit_size; i += 4)
 126                        PSB_WSGX32(*cmdbuf++, PSB_SGX_2D_SLAVE_PORT + i);
 127
 128                (void)PSB_RSGX32(PSB_SGX_2D_SLAVE_PORT + i - 4);
 129        }
 130        spin_unlock_irqrestore(&dev_priv->lock_2d, flags);
 131        return ret;
 132}
 133
 134
 135/**
 136 *      psb_accel_2d_copy_direction     -       compute blit order
 137 *      @xdir: X direction of move
 138 *      @ydir: Y direction of move
 139 *
 140 *      Compute the correct order setings to ensure that an overlapping blit
 141 *      correctly copies all the pixels.
 142 */
 143static u32 psb_accel_2d_copy_direction(int xdir, int ydir)
 144{
 145        if (xdir < 0)
 146                return (ydir < 0) ? PSB_2D_COPYORDER_BR2TL :
 147                                                PSB_2D_COPYORDER_TR2BL;
 148        else
 149                return (ydir < 0) ? PSB_2D_COPYORDER_BL2TR :
 150                                                PSB_2D_COPYORDER_TL2BR;
 151}
 152
 153/**
 154 *      psb_accel_2d_copy               -       accelerated 2D copy
 155 *      @dev_priv: our DRM device
 156 *      @src_offset in bytes
 157 *      @src_stride in bytes
 158 *      @src_format psb 2D format defines
 159 *      @dst_offset in bytes
 160 *      @dst_stride in bytes
 161 *      @dst_format psb 2D format defines
 162 *      @src_x offset in pixels
 163 *      @src_y offset in pixels
 164 *      @dst_x offset in pixels
 165 *      @dst_y offset in pixels
 166 *      @size_x of the copied area
 167 *      @size_y of the copied area
 168 *
 169 *      Format and issue a 2D accelerated copy command.
 170 */
 171static int psb_accel_2d_copy(struct drm_psb_private *dev_priv,
 172                             uint32_t src_offset, uint32_t src_stride,
 173                             uint32_t src_format, uint32_t dst_offset,
 174                             uint32_t dst_stride, uint32_t dst_format,
 175                             uint16_t src_x, uint16_t src_y,
 176                             uint16_t dst_x, uint16_t dst_y,
 177                             uint16_t size_x, uint16_t size_y)
 178{
 179        uint32_t blit_cmd;
 180        uint32_t buffer[10];
 181        uint32_t *buf;
 182        uint32_t direction;
 183
 184        buf = buffer;
 185
 186        direction =
 187            psb_accel_2d_copy_direction(src_x - dst_x, src_y - dst_y);
 188
 189        if (direction == PSB_2D_COPYORDER_BR2TL ||
 190            direction == PSB_2D_COPYORDER_TR2BL) {
 191                src_x += size_x - 1;
 192                dst_x += size_x - 1;
 193        }
 194        if (direction == PSB_2D_COPYORDER_BR2TL ||
 195            direction == PSB_2D_COPYORDER_BL2TR) {
 196                src_y += size_y - 1;
 197                dst_y += size_y - 1;
 198        }
 199
 200        blit_cmd =
 201            PSB_2D_BLIT_BH |
 202            PSB_2D_ROT_NONE |
 203            PSB_2D_DSTCK_DISABLE |
 204            PSB_2D_SRCCK_DISABLE |
 205            PSB_2D_USE_PAT | PSB_2D_ROP3_SRCCOPY | direction;
 206
 207        *buf++ = PSB_2D_FENCE_BH;
 208        *buf++ =
 209            PSB_2D_DST_SURF_BH | dst_format | (dst_stride <<
 210                                               PSB_2D_DST_STRIDE_SHIFT);
 211        *buf++ = dst_offset;
 212        *buf++ =
 213            PSB_2D_SRC_SURF_BH | src_format | (src_stride <<
 214                                               PSB_2D_SRC_STRIDE_SHIFT);
 215        *buf++ = src_offset;
 216        *buf++ =
 217            PSB_2D_SRC_OFF_BH | (src_x << PSB_2D_SRCOFF_XSTART_SHIFT) |
 218            (src_y << PSB_2D_SRCOFF_YSTART_SHIFT);
 219        *buf++ = blit_cmd;
 220        *buf++ =
 221            (dst_x << PSB_2D_DST_XSTART_SHIFT) | (dst_y <<
 222                                                  PSB_2D_DST_YSTART_SHIFT);
 223        *buf++ =
 224            (size_x << PSB_2D_DST_XSIZE_SHIFT) | (size_y <<
 225                                                  PSB_2D_DST_YSIZE_SHIFT);
 226        *buf++ = PSB_2D_FLUSH_BH;
 227
 228        return psbfb_2d_submit(dev_priv, buffer, buf - buffer);
 229}
 230
 231/**
 232 *      psbfb_copyarea_accel    -       copyarea acceleration for /dev/fb
 233 *      @info: our framebuffer
 234 *      @a: copyarea parameters from the framebuffer core
 235 *
 236 *      Perform a 2D copy via the accelerator
 237 */
 238static void psbfb_copyarea_accel(struct fb_info *info,
 239                                 const struct fb_copyarea *a)
 240{
 241        struct psb_fbdev *fbdev = info->par;
 242        struct psb_framebuffer *psbfb = &fbdev->pfb;
 243        struct drm_device *dev = psbfb->base.dev;
 244        struct drm_framebuffer *fb = fbdev->psb_fb_helper.fb;
 245        struct drm_psb_private *dev_priv = dev->dev_private;
 246        uint32_t offset;
 247        uint32_t stride;
 248        uint32_t src_format;
 249        uint32_t dst_format;
 250
 251        if (!fb)
 252                return;
 253
 254        offset = psbfb->gtt->offset;
 255        stride = fb->pitches[0];
 256
 257        switch (fb->format->depth) {
 258        case 8:
 259                src_format = PSB_2D_SRC_332RGB;
 260                dst_format = PSB_2D_DST_332RGB;
 261                break;
 262        case 15:
 263                src_format = PSB_2D_SRC_555RGB;
 264                dst_format = PSB_2D_DST_555RGB;
 265                break;
 266        case 16:
 267                src_format = PSB_2D_SRC_565RGB;
 268                dst_format = PSB_2D_DST_565RGB;
 269                break;
 270        case 24:
 271        case 32:
 272                /* this is wrong but since we don't do blending its okay */
 273                src_format = PSB_2D_SRC_8888ARGB;
 274                dst_format = PSB_2D_DST_8888ARGB;
 275                break;
 276        default:
 277                /* software fallback */
 278                drm_fb_helper_cfb_copyarea(info, a);
 279                return;
 280        }
 281
 282        if (!gma_power_begin(dev, false)) {
 283                drm_fb_helper_cfb_copyarea(info, a);
 284                return;
 285        }
 286        psb_accel_2d_copy(dev_priv,
 287                          offset, stride, src_format,
 288                          offset, stride, dst_format,
 289                          a->sx, a->sy, a->dx, a->dy, a->width, a->height);
 290        gma_power_end(dev);
 291}
 292
 293/**
 294 *      psbfb_copyarea  -       2D copy interface
 295 *      @info: our framebuffer
 296 *      @region: region to copy
 297 *
 298 *      Copy an area of the framebuffer console either by the accelerator
 299 *      or directly using the cfb helpers according to the request
 300 */
 301void psbfb_copyarea(struct fb_info *info,
 302                           const struct fb_copyarea *region)
 303{
 304        if (unlikely(info->state != FBINFO_STATE_RUNNING))
 305                return;
 306
 307        /* Avoid the 8 pixel erratum */
 308        if (region->width == 8 || region->height == 8 ||
 309                (info->flags & FBINFO_HWACCEL_DISABLED))
 310                return drm_fb_helper_cfb_copyarea(info, region);
 311
 312        psbfb_copyarea_accel(info, region);
 313}
 314
 315/**
 316 *      psbfb_sync      -       synchronize 2D
 317 *      @info: our framebuffer
 318 *
 319 *      Wait for the 2D engine to quiesce so that we can do CPU
 320 *      access to the framebuffer again
 321 */
 322int psbfb_sync(struct fb_info *info)
 323{
 324        struct psb_fbdev *fbdev = info->par;
 325        struct psb_framebuffer *psbfb = &fbdev->pfb;
 326        struct drm_device *dev = psbfb->base.dev;
 327        struct drm_psb_private *dev_priv = dev->dev_private;
 328        unsigned long _end = jiffies + HZ;
 329        int busy = 0;
 330        unsigned long flags;
 331
 332        spin_lock_irqsave(&dev_priv->lock_2d, flags);
 333        /*
 334         * First idle the 2D engine.
 335         */
 336
 337        if ((PSB_RSGX32(PSB_CR_2D_SOCIF) == _PSB_C2_SOCIF_EMPTY) &&
 338            ((PSB_RSGX32(PSB_CR_2D_BLIT_STATUS) & _PSB_C2B_STATUS_BUSY) == 0))
 339                goto out;
 340
 341        do {
 342                busy = (PSB_RSGX32(PSB_CR_2D_SOCIF) != _PSB_C2_SOCIF_EMPTY);
 343                cpu_relax();
 344        } while (busy && !time_after_eq(jiffies, _end));
 345
 346        if (busy)
 347                busy = (PSB_RSGX32(PSB_CR_2D_SOCIF) != _PSB_C2_SOCIF_EMPTY);
 348        if (busy)
 349                goto out;
 350
 351        do {
 352                busy = ((PSB_RSGX32(PSB_CR_2D_BLIT_STATUS) &
 353                                                _PSB_C2B_STATUS_BUSY) != 0);
 354                cpu_relax();
 355        } while (busy && !time_after_eq(jiffies, _end));
 356        if (busy)
 357                busy = ((PSB_RSGX32(PSB_CR_2D_BLIT_STATUS) &
 358                                        _PSB_C2B_STATUS_BUSY) != 0);
 359
 360out:
 361        spin_unlock_irqrestore(&dev_priv->lock_2d, flags);
 362        return (busy) ? -EBUSY : 0;
 363}
 364