linux/drivers/staging/sm750fb/sm750_accel.c
<<
>>
Prefs
   1#include <linux/module.h>
   2#include <linux/kernel.h>
   3#include <linux/errno.h>
   4#include <linux/string.h>
   5#include <linux/mm.h>
   6#include <linux/slab.h>
   7#include <linux/delay.h>
   8#include <linux/fb.h>
   9#include <linux/ioport.h>
  10#include <linux/init.h>
  11#include <linux/pci.h>
  12#include <linux/vmalloc.h>
  13#include <linux/pagemap.h>
  14#include <linux/console.h>
  15#include <linux/platform_device.h>
  16#include <linux/screen_info.h>
  17
  18#include "sm750.h"
  19#include "sm750_accel.h"
  20static inline void write_dpr(struct lynx_accel *accel, int offset, u32 regValue)
  21{
  22        writel(regValue, accel->dprBase + offset);
  23}
  24
  25static inline u32 read_dpr(struct lynx_accel *accel, int offset)
  26{
  27        return readl(accel->dprBase + offset);
  28}
  29
  30static inline void write_dpPort(struct lynx_accel *accel, u32 data)
  31{
  32        writel(data, accel->dpPortBase);
  33}
  34
  35void hw_de_init(struct lynx_accel *accel)
  36{
  37        /* setup 2d engine registers */
  38        u32 reg, clr;
  39
  40        write_dpr(accel, DE_MASKS, 0xFFFFFFFF);
  41
  42        /* dpr1c */
  43        reg =  0x3;
  44
  45        clr = DE_STRETCH_FORMAT_PATTERN_XY | DE_STRETCH_FORMAT_PATTERN_Y_MASK |
  46                DE_STRETCH_FORMAT_PATTERN_X_MASK |
  47                DE_STRETCH_FORMAT_ADDRESSING_MASK |
  48                DE_STRETCH_FORMAT_SOURCE_HEIGHT_MASK;
  49
  50        /* DE_STRETCH bpp format need be initialized in setMode routine */
  51        write_dpr(accel, DE_STRETCH_FORMAT,
  52                  (read_dpr(accel, DE_STRETCH_FORMAT) & ~clr) | reg);
  53
  54        /* disable clipping and transparent */
  55        write_dpr(accel, DE_CLIP_TL, 0); /* dpr2c */
  56        write_dpr(accel, DE_CLIP_BR, 0); /* dpr30 */
  57
  58        write_dpr(accel, DE_COLOR_COMPARE_MASK, 0); /* dpr24 */
  59        write_dpr(accel, DE_COLOR_COMPARE, 0);
  60
  61        clr = DE_CONTROL_TRANSPARENCY | DE_CONTROL_TRANSPARENCY_MATCH |
  62                DE_CONTROL_TRANSPARENCY_SELECT;
  63
  64        /* dpr0c */
  65        write_dpr(accel, DE_CONTROL, read_dpr(accel, DE_CONTROL) & ~clr);
  66}
  67
  68/* set2dformat only be called from setmode functions
  69 * but if you need dual framebuffer driver,need call set2dformat
  70 * every time you use 2d function */
  71
  72void hw_set2dformat(struct lynx_accel *accel, int fmt)
  73{
  74        u32 reg;
  75
  76        /* fmt=0,1,2 for 8,16,32,bpp on sm718/750/502 */
  77        reg = read_dpr(accel, DE_STRETCH_FORMAT);
  78        reg &= ~DE_STRETCH_FORMAT_PIXEL_FORMAT_MASK;
  79        reg |= ((fmt << DE_STRETCH_FORMAT_PIXEL_FORMAT_SHIFT) &
  80                DE_STRETCH_FORMAT_PIXEL_FORMAT_MASK);
  81        write_dpr(accel, DE_STRETCH_FORMAT, reg);
  82}
  83
  84int hw_fillrect(struct lynx_accel *accel,
  85                                u32 base, u32 pitch, u32 Bpp,
  86                                u32 x, u32 y, u32 width, u32 height,
  87                                u32 color, u32 rop)
  88{
  89        u32 deCtrl;
  90
  91        if (accel->de_wait() != 0) {
  92                /* int time wait and always busy,seems hardware
  93                 * got something error */
  94                pr_debug("De engine always busy\n");
  95                return -1;
  96        }
  97
  98        write_dpr(accel, DE_WINDOW_DESTINATION_BASE, base); /* dpr40 */
  99        write_dpr(accel, DE_PITCH,
 100                  ((pitch / Bpp << DE_PITCH_DESTINATION_SHIFT) &
 101                   DE_PITCH_DESTINATION_MASK) |
 102                  (pitch / Bpp & DE_PITCH_SOURCE_MASK)); /* dpr10 */
 103
 104        write_dpr(accel, DE_WINDOW_WIDTH,
 105                  ((pitch / Bpp << DE_WINDOW_WIDTH_DST_SHIFT) &
 106                   DE_WINDOW_WIDTH_DST_MASK) |
 107                   (pitch / Bpp & DE_WINDOW_WIDTH_SRC_MASK)); /* dpr44 */
 108
 109        write_dpr(accel, DE_FOREGROUND, color); /* DPR14 */
 110
 111        write_dpr(accel, DE_DESTINATION,
 112                  ((x << DE_DESTINATION_X_SHIFT) & DE_DESTINATION_X_MASK) |
 113                  (y & DE_DESTINATION_Y_MASK)); /* dpr4 */
 114
 115        write_dpr(accel, DE_DIMENSION,
 116                  ((width << DE_DIMENSION_X_SHIFT) & DE_DIMENSION_X_MASK) |
 117                  (height & DE_DIMENSION_Y_ET_MASK)); /* dpr8 */
 118
 119        deCtrl = DE_CONTROL_STATUS | DE_CONTROL_LAST_PIXEL |
 120                DE_CONTROL_COMMAND_RECTANGLE_FILL | DE_CONTROL_ROP_SELECT |
 121                (rop & DE_CONTROL_ROP_MASK); /* dpr0xc */
 122
 123        write_dpr(accel, DE_CONTROL, deCtrl);
 124        return 0;
 125}
 126
 127int hw_copyarea(
 128struct lynx_accel *accel,
 129unsigned int sBase,  /* Address of source: offset in frame buffer */
 130unsigned int sPitch, /* Pitch value of source surface in BYTE */
 131unsigned int sx,
 132unsigned int sy,     /* Starting coordinate of source surface */
 133unsigned int dBase,  /* Address of destination: offset in frame buffer */
 134unsigned int dPitch, /* Pitch value of destination surface in BYTE */
 135unsigned int Bpp,    /* Color depth of destination surface */
 136unsigned int dx,
 137unsigned int dy,     /* Starting coordinate of destination surface */
 138unsigned int width,
 139unsigned int height, /* width and height of rectangle in pixel value */
 140unsigned int rop2)   /* ROP value */
 141{
 142        unsigned int nDirection, de_ctrl;
 143        int opSign;
 144
 145        nDirection = LEFT_TO_RIGHT;
 146        /* Direction of ROP2 operation: 1 = Left to Right, (-1) = Right to Left */
 147        opSign = 1;
 148        de_ctrl = 0;
 149
 150        /* If source and destination are the same surface, need to check for overlay cases */
 151        if (sBase == dBase && sPitch == dPitch) {
 152                /* Determine direction of operation */
 153                if (sy < dy) {
 154                        /* +----------+
 155                           |S         |
 156                           |   +----------+
 157                           |   |      |   |
 158                           |   |      |   |
 159                           +---|------+   |
 160                           |         D|
 161                           +----------+ */
 162
 163                        nDirection = BOTTOM_TO_TOP;
 164                } else if (sy > dy) {
 165                        /* +----------+
 166                           |D         |
 167                           |   +----------+
 168                           |   |      |   |
 169                           |   |      |   |
 170                           +---|------+   |
 171                           |         S|
 172                           +----------+ */
 173
 174                        nDirection = TOP_TO_BOTTOM;
 175                } else {
 176                        /* sy == dy */
 177
 178                        if (sx <= dx) {
 179                                /* +------+---+------+
 180                                   |S     |   |     D|
 181                                   |      |   |      |
 182                                   |      |   |      |
 183                                   |      |   |      |
 184                                   +------+---+------+ */
 185
 186                                nDirection = RIGHT_TO_LEFT;
 187                        } else {
 188                        /* sx > dx */
 189
 190                                /* +------+---+------+
 191                                   |D     |   |     S|
 192                                   |      |   |      |
 193                                   |      |   |      |
 194                                   |      |   |      |
 195                                   +------+---+------+ */
 196
 197                                nDirection = LEFT_TO_RIGHT;
 198                        }
 199                }
 200        }
 201
 202        if ((nDirection == BOTTOM_TO_TOP) || (nDirection == RIGHT_TO_LEFT)) {
 203                sx += width - 1;
 204                sy += height - 1;
 205                dx += width - 1;
 206                dy += height - 1;
 207                opSign = (-1);
 208        }
 209
 210        /* Note:
 211           DE_FOREGROUND are DE_BACKGROUND are don't care.
 212          DE_COLOR_COMPARE and DE_COLOR_COMPARE_MAKS are set by set deSetTransparency().
 213         */
 214
 215        /* 2D Source Base.
 216         It is an address offset (128 bit aligned) from the beginning of frame buffer.
 217         */
 218        write_dpr(accel, DE_WINDOW_SOURCE_BASE, sBase); /* dpr40 */
 219
 220        /* 2D Destination Base.
 221         It is an address offset (128 bit aligned) from the beginning of frame buffer.
 222         */
 223        write_dpr(accel, DE_WINDOW_DESTINATION_BASE, dBase); /* dpr44 */
 224
 225    /* Program pitch (distance between the 1st points of two adjacent lines).
 226       Note that input pitch is BYTE value, but the 2D Pitch register uses
 227       pixel values. Need Byte to pixel conversion.
 228    */
 229        write_dpr(accel, DE_PITCH,
 230                  ((dPitch / Bpp << DE_PITCH_DESTINATION_SHIFT) &
 231                   DE_PITCH_DESTINATION_MASK) |
 232                  (sPitch / Bpp & DE_PITCH_SOURCE_MASK)); /* dpr10 */
 233
 234    /* Screen Window width in Pixels.
 235       2D engine uses this value to calculate the linear address in frame buffer for a given point.
 236    */
 237        write_dpr(accel, DE_WINDOW_WIDTH,
 238                  ((dPitch / Bpp << DE_WINDOW_WIDTH_DST_SHIFT) &
 239                   DE_WINDOW_WIDTH_DST_MASK) |
 240                  (sPitch / Bpp & DE_WINDOW_WIDTH_SRC_MASK)); /* dpr3c */
 241
 242        if (accel->de_wait() != 0)
 243                return -1;
 244
 245        {
 246
 247        write_dpr(accel, DE_SOURCE,
 248                  ((sx << DE_SOURCE_X_K1_SHIFT) & DE_SOURCE_X_K1_MASK) |
 249                  (sy & DE_SOURCE_Y_K2_MASK)); /* dpr0 */
 250        write_dpr(accel, DE_DESTINATION,
 251                  ((dx << DE_DESTINATION_X_SHIFT) & DE_DESTINATION_X_MASK) |
 252                  (dy & DE_DESTINATION_Y_MASK)); /* dpr04 */
 253        write_dpr(accel, DE_DIMENSION,
 254                  ((width << DE_DIMENSION_X_SHIFT) & DE_DIMENSION_X_MASK) |
 255                  (height & DE_DIMENSION_Y_ET_MASK)); /* dpr08 */
 256
 257        de_ctrl = (rop2 & DE_CONTROL_ROP_MASK) | DE_CONTROL_ROP_SELECT |
 258                ((nDirection == RIGHT_TO_LEFT) ? DE_CONTROL_DIRECTION : 0) |
 259                DE_CONTROL_COMMAND_BITBLT | DE_CONTROL_STATUS;
 260        write_dpr(accel, DE_CONTROL, de_ctrl); /* dpr0c */
 261
 262        }
 263
 264        return 0;
 265}
 266
 267static unsigned int deGetTransparency(struct lynx_accel *accel)
 268{
 269        unsigned int de_ctrl;
 270
 271        de_ctrl = read_dpr(accel, DE_CONTROL);
 272
 273        de_ctrl &= (DE_CONTROL_TRANSPARENCY_MATCH |
 274                    DE_CONTROL_TRANSPARENCY_SELECT | DE_CONTROL_TRANSPARENCY);
 275
 276        return de_ctrl;
 277}
 278
 279int hw_imageblit(struct lynx_accel *accel,
 280                 const char *pSrcbuf, /* pointer to start of source buffer in system memory */
 281                 u32 srcDelta,          /* Pitch value (in bytes) of the source buffer, +ive means top down and -ive mean button up */
 282                 u32 startBit, /* Mono data can start at any bit in a byte, this value should be 0 to 7 */
 283                 u32 dBase,    /* Address of destination: offset in frame buffer */
 284                 u32 dPitch,   /* Pitch value of destination surface in BYTE */
 285                 u32 bytePerPixel,      /* Color depth of destination surface */
 286                 u32 dx,
 287                 u32 dy,       /* Starting coordinate of destination surface */
 288                 u32 width,
 289                 u32 height,   /* width and height of rectangle in pixel value */
 290                 u32 fColor,   /* Foreground color (corresponding to a 1 in the monochrome data */
 291                 u32 bColor,   /* Background color (corresponding to a 0 in the monochrome data */
 292                 u32 rop2)     /* ROP value */
 293{
 294        unsigned int ulBytesPerScan;
 295        unsigned int ul4BytesPerScan;
 296        unsigned int ulBytesRemain;
 297        unsigned int de_ctrl = 0;
 298        unsigned char ajRemain[4];
 299        int i, j;
 300
 301        startBit &= 7; /* Just make sure the start bit is within legal range */
 302        ulBytesPerScan = (width + startBit + 7) / 8;
 303        ul4BytesPerScan = ulBytesPerScan & ~3;
 304        ulBytesRemain = ulBytesPerScan & 3;
 305
 306        if (accel->de_wait() != 0)
 307                return -1;
 308
 309        /* 2D Source Base.
 310         Use 0 for HOST Blt.
 311         */
 312        write_dpr(accel, DE_WINDOW_SOURCE_BASE, 0);
 313
 314        /* 2D Destination Base.
 315         It is an address offset (128 bit aligned) from the beginning of frame buffer.
 316         */
 317        write_dpr(accel, DE_WINDOW_DESTINATION_BASE, dBase);
 318    /* Program pitch (distance between the 1st points of two adjacent lines).
 319       Note that input pitch is BYTE value, but the 2D Pitch register uses
 320       pixel values. Need Byte to pixel conversion.
 321    */
 322        write_dpr(accel, DE_PITCH,
 323                  ((dPitch / bytePerPixel << DE_PITCH_DESTINATION_SHIFT) &
 324                   DE_PITCH_DESTINATION_MASK) |
 325                  (dPitch / bytePerPixel & DE_PITCH_SOURCE_MASK)); /* dpr10 */
 326
 327        /* Screen Window width in Pixels.
 328         2D engine uses this value to calculate the linear address in frame buffer for a given point.
 329         */
 330        write_dpr(accel, DE_WINDOW_WIDTH,
 331                  ((dPitch / bytePerPixel << DE_WINDOW_WIDTH_DST_SHIFT) &
 332                   DE_WINDOW_WIDTH_DST_MASK) |
 333                  (dPitch / bytePerPixel & DE_WINDOW_WIDTH_SRC_MASK));
 334
 335         /* Note: For 2D Source in Host Write, only X_K1_MONO field is needed, and Y_K2 field is not used.
 336            For mono bitmap, use startBit for X_K1. */
 337        write_dpr(accel, DE_SOURCE,
 338                  (startBit << DE_SOURCE_X_K1_SHIFT) &
 339                  DE_SOURCE_X_K1_MONO_MASK); /* dpr00 */
 340
 341        write_dpr(accel, DE_DESTINATION,
 342                  ((dx << DE_DESTINATION_X_SHIFT) & DE_DESTINATION_X_MASK) |
 343                  (dy & DE_DESTINATION_Y_MASK)); /* dpr04 */
 344
 345        write_dpr(accel, DE_DIMENSION,
 346                  ((width << DE_DIMENSION_X_SHIFT) & DE_DIMENSION_X_MASK) |
 347                  (height & DE_DIMENSION_Y_ET_MASK)); /* dpr08 */
 348
 349        write_dpr(accel, DE_FOREGROUND, fColor);
 350        write_dpr(accel, DE_BACKGROUND, bColor);
 351
 352        de_ctrl = (rop2 & DE_CONTROL_ROP_MASK) |
 353                DE_CONTROL_ROP_SELECT | DE_CONTROL_COMMAND_HOST_WRITE |
 354                DE_CONTROL_HOST | DE_CONTROL_STATUS;
 355
 356        write_dpr(accel, DE_CONTROL, de_ctrl | deGetTransparency(accel));
 357
 358        /* Write MONO data (line by line) to 2D Engine data port */
 359        for (i = 0; i < height; i++) {
 360                /* For each line, send the data in chunks of 4 bytes */
 361                for (j = 0; j < (ul4BytesPerScan/4); j++)
 362                        write_dpPort(accel, *(unsigned int *)(pSrcbuf + (j * 4)));
 363
 364                if (ulBytesRemain) {
 365                        memcpy(ajRemain, pSrcbuf+ul4BytesPerScan, ulBytesRemain);
 366                        write_dpPort(accel, *(unsigned int *)ajRemain);
 367                }
 368
 369                pSrcbuf += srcDelta;
 370        }
 371
 372            return 0;
 373}
 374
 375