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