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