linux/drivers/video/fbdev/via/accel.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
   4 * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
   5
   6 */
   7#include <linux/via-core.h>
   8#include "global.h"
   9
  10/*
  11 * Figure out an appropriate bytes-per-pixel setting.
  12 */
  13static int viafb_set_bpp(void __iomem *engine, u8 bpp)
  14{
  15        u32 gemode;
  16
  17        /* Preserve the reserved bits */
  18        /* Lowest 2 bits to zero gives us no rotation */
  19        gemode = readl(engine + VIA_REG_GEMODE) & 0xfffffcfc;
  20        switch (bpp) {
  21        case 8:
  22                gemode |= VIA_GEM_8bpp;
  23                break;
  24        case 16:
  25                gemode |= VIA_GEM_16bpp;
  26                break;
  27        case 32:
  28                gemode |= VIA_GEM_32bpp;
  29                break;
  30        default:
  31                printk(KERN_WARNING "viafb_set_bpp: Unsupported bpp %d\n", bpp);
  32                return -EINVAL;
  33        }
  34        writel(gemode, engine + VIA_REG_GEMODE);
  35        return 0;
  36}
  37
  38
  39static int hw_bitblt_1(void __iomem *engine, u8 op, u32 width, u32 height,
  40        u8 dst_bpp, u32 dst_addr, u32 dst_pitch, u32 dst_x, u32 dst_y,
  41        u32 *src_mem, u32 src_addr, u32 src_pitch, u32 src_x, u32 src_y,
  42        u32 fg_color, u32 bg_color, u8 fill_rop)
  43{
  44        u32 ge_cmd = 0, tmp, i;
  45        int ret;
  46
  47        if (!op || op > 3) {
  48                printk(KERN_WARNING "hw_bitblt_1: Invalid operation: %d\n", op);
  49                return -EINVAL;
  50        }
  51
  52        if (op != VIA_BITBLT_FILL && !src_mem && src_addr == dst_addr) {
  53                if (src_x < dst_x) {
  54                        ge_cmd |= 0x00008000;
  55                        src_x += width - 1;
  56                        dst_x += width - 1;
  57                }
  58                if (src_y < dst_y) {
  59                        ge_cmd |= 0x00004000;
  60                        src_y += height - 1;
  61                        dst_y += height - 1;
  62                }
  63        }
  64
  65        if (op == VIA_BITBLT_FILL) {
  66                switch (fill_rop) {
  67                case 0x00: /* blackness */
  68                case 0x5A: /* pattern inversion */
  69                case 0xF0: /* pattern copy */
  70                case 0xFF: /* whiteness */
  71                        break;
  72                default:
  73                        printk(KERN_WARNING "hw_bitblt_1: Invalid fill rop: "
  74                                "%u\n", fill_rop);
  75                        return -EINVAL;
  76                }
  77        }
  78
  79        ret = viafb_set_bpp(engine, dst_bpp);
  80        if (ret)
  81                return ret;
  82
  83        if (op != VIA_BITBLT_FILL) {
  84                if (src_x & (op == VIA_BITBLT_MONO ? 0xFFFF8000 : 0xFFFFF000)
  85                        || src_y & 0xFFFFF000) {
  86                        printk(KERN_WARNING "hw_bitblt_1: Unsupported source "
  87                                "x/y %d %d\n", src_x, src_y);
  88                        return -EINVAL;
  89                }
  90                tmp = src_x | (src_y << 16);
  91                writel(tmp, engine + 0x08);
  92        }
  93
  94        if (dst_x & 0xFFFFF000 || dst_y & 0xFFFFF000) {
  95                printk(KERN_WARNING "hw_bitblt_1: Unsupported destination x/y "
  96                        "%d %d\n", dst_x, dst_y);
  97                return -EINVAL;
  98        }
  99        tmp = dst_x | (dst_y << 16);
 100        writel(tmp, engine + 0x0C);
 101
 102        if ((width - 1) & 0xFFFFF000 || (height - 1) & 0xFFFFF000) {
 103                printk(KERN_WARNING "hw_bitblt_1: Unsupported width/height "
 104                        "%d %d\n", width, height);
 105                return -EINVAL;
 106        }
 107        tmp = (width - 1) | ((height - 1) << 16);
 108        writel(tmp, engine + 0x10);
 109
 110        if (op != VIA_BITBLT_COLOR)
 111                writel(fg_color, engine + 0x18);
 112
 113        if (op == VIA_BITBLT_MONO)
 114                writel(bg_color, engine + 0x1C);
 115
 116        if (op != VIA_BITBLT_FILL) {
 117                tmp = src_mem ? 0 : src_addr;
 118                if (dst_addr & 0xE0000007) {
 119                        printk(KERN_WARNING "hw_bitblt_1: Unsupported source "
 120                                "address %X\n", tmp);
 121                        return -EINVAL;
 122                }
 123                tmp >>= 3;
 124                writel(tmp, engine + 0x30);
 125        }
 126
 127        if (dst_addr & 0xE0000007) {
 128                printk(KERN_WARNING "hw_bitblt_1: Unsupported destination "
 129                        "address %X\n", dst_addr);
 130                return -EINVAL;
 131        }
 132        tmp = dst_addr >> 3;
 133        writel(tmp, engine + 0x34);
 134
 135        if (op == VIA_BITBLT_FILL)
 136                tmp = 0;
 137        else
 138                tmp = src_pitch;
 139        if (tmp & 0xFFFFC007 || dst_pitch & 0xFFFFC007) {
 140                printk(KERN_WARNING "hw_bitblt_1: Unsupported pitch %X %X\n",
 141                        tmp, dst_pitch);
 142                return -EINVAL;
 143        }
 144        tmp = VIA_PITCH_ENABLE | (tmp >> 3) | (dst_pitch << (16 - 3));
 145        writel(tmp, engine + 0x38);
 146
 147        if (op == VIA_BITBLT_FILL)
 148                ge_cmd |= fill_rop << 24 | 0x00002000 | 0x00000001;
 149        else {
 150                ge_cmd |= 0xCC000000; /* ROP=SRCCOPY */
 151                if (src_mem)
 152                        ge_cmd |= 0x00000040;
 153                if (op == VIA_BITBLT_MONO)
 154                        ge_cmd |= 0x00000002 | 0x00000100 | 0x00020000;
 155                else
 156                        ge_cmd |= 0x00000001;
 157        }
 158        writel(ge_cmd, engine);
 159
 160        if (op == VIA_BITBLT_FILL || !src_mem)
 161                return 0;
 162
 163        tmp = (width * height * (op == VIA_BITBLT_MONO ? 1 : (dst_bpp >> 3)) +
 164                3) >> 2;
 165
 166        for (i = 0; i < tmp; i++)
 167                writel(src_mem[i], engine + VIA_MMIO_BLTBASE);
 168
 169        return 0;
 170}
 171
 172static int hw_bitblt_2(void __iomem *engine, u8 op, u32 width, u32 height,
 173        u8 dst_bpp, u32 dst_addr, u32 dst_pitch, u32 dst_x, u32 dst_y,
 174        u32 *src_mem, u32 src_addr, u32 src_pitch, u32 src_x, u32 src_y,
 175        u32 fg_color, u32 bg_color, u8 fill_rop)
 176{
 177        u32 ge_cmd = 0, tmp, i;
 178        int ret;
 179
 180        if (!op || op > 3) {
 181                printk(KERN_WARNING "hw_bitblt_2: Invalid operation: %d\n", op);
 182                return -EINVAL;
 183        }
 184
 185        if (op != VIA_BITBLT_FILL && !src_mem && src_addr == dst_addr) {
 186                if (src_x < dst_x) {
 187                        ge_cmd |= 0x00008000;
 188                        src_x += width - 1;
 189                        dst_x += width - 1;
 190                }
 191                if (src_y < dst_y) {
 192                        ge_cmd |= 0x00004000;
 193                        src_y += height - 1;
 194                        dst_y += height - 1;
 195                }
 196        }
 197
 198        if (op == VIA_BITBLT_FILL) {
 199                switch (fill_rop) {
 200                case 0x00: /* blackness */
 201                case 0x5A: /* pattern inversion */
 202                case 0xF0: /* pattern copy */
 203                case 0xFF: /* whiteness */
 204                        break;
 205                default:
 206                        printk(KERN_WARNING "hw_bitblt_2: Invalid fill rop: "
 207                                "%u\n", fill_rop);
 208                        return -EINVAL;
 209                }
 210        }
 211
 212        ret = viafb_set_bpp(engine, dst_bpp);
 213        if (ret)
 214                return ret;
 215
 216        if (op == VIA_BITBLT_FILL)
 217                tmp = 0;
 218        else
 219                tmp = src_pitch;
 220        if (tmp & 0xFFFFC007 || dst_pitch & 0xFFFFC007) {
 221                printk(KERN_WARNING "hw_bitblt_2: Unsupported pitch %X %X\n",
 222                        tmp, dst_pitch);
 223                return -EINVAL;
 224        }
 225        tmp = (tmp >> 3) | (dst_pitch << (16 - 3));
 226        writel(tmp, engine + 0x08);
 227
 228        if ((width - 1) & 0xFFFFF000 || (height - 1) & 0xFFFFF000) {
 229                printk(KERN_WARNING "hw_bitblt_2: Unsupported width/height "
 230                        "%d %d\n", width, height);
 231                return -EINVAL;
 232        }
 233        tmp = (width - 1) | ((height - 1) << 16);
 234        writel(tmp, engine + 0x0C);
 235
 236        if (dst_x & 0xFFFFF000 || dst_y & 0xFFFFF000) {
 237                printk(KERN_WARNING "hw_bitblt_2: Unsupported destination x/y "
 238                        "%d %d\n", dst_x, dst_y);
 239                return -EINVAL;
 240        }
 241        tmp = dst_x | (dst_y << 16);
 242        writel(tmp, engine + 0x10);
 243
 244        if (dst_addr & 0xE0000007) {
 245                printk(KERN_WARNING "hw_bitblt_2: Unsupported destination "
 246                        "address %X\n", dst_addr);
 247                return -EINVAL;
 248        }
 249        tmp = dst_addr >> 3;
 250        writel(tmp, engine + 0x14);
 251
 252        if (op != VIA_BITBLT_FILL) {
 253                if (src_x & (op == VIA_BITBLT_MONO ? 0xFFFF8000 : 0xFFFFF000)
 254                        || src_y & 0xFFFFF000) {
 255                        printk(KERN_WARNING "hw_bitblt_2: Unsupported source "
 256                                "x/y %d %d\n", src_x, src_y);
 257                        return -EINVAL;
 258                }
 259                tmp = src_x | (src_y << 16);
 260                writel(tmp, engine + 0x18);
 261
 262                tmp = src_mem ? 0 : src_addr;
 263                if (dst_addr & 0xE0000007) {
 264                        printk(KERN_WARNING "hw_bitblt_2: Unsupported source "
 265                                "address %X\n", tmp);
 266                        return -EINVAL;
 267                }
 268                tmp >>= 3;
 269                writel(tmp, engine + 0x1C);
 270        }
 271
 272        if (op == VIA_BITBLT_FILL) {
 273                writel(fg_color, engine + 0x58);
 274        } else if (op == VIA_BITBLT_MONO) {
 275                writel(fg_color, engine + 0x4C);
 276                writel(bg_color, engine + 0x50);
 277        }
 278
 279        if (op == VIA_BITBLT_FILL)
 280                ge_cmd |= fill_rop << 24 | 0x00002000 | 0x00000001;
 281        else {
 282                ge_cmd |= 0xCC000000; /* ROP=SRCCOPY */
 283                if (src_mem)
 284                        ge_cmd |= 0x00000040;
 285                if (op == VIA_BITBLT_MONO)
 286                        ge_cmd |= 0x00000002 | 0x00000100 | 0x00020000;
 287                else
 288                        ge_cmd |= 0x00000001;
 289        }
 290        writel(ge_cmd, engine);
 291
 292        if (op == VIA_BITBLT_FILL || !src_mem)
 293                return 0;
 294
 295        tmp = (width * height * (op == VIA_BITBLT_MONO ? 1 : (dst_bpp >> 3)) +
 296                3) >> 2;
 297
 298        for (i = 0; i < tmp; i++)
 299                writel(src_mem[i], engine + VIA_MMIO_BLTBASE);
 300
 301        return 0;
 302}
 303
 304int viafb_setup_engine(struct fb_info *info)
 305{
 306        struct viafb_par *viapar = info->par;
 307        void __iomem *engine;
 308        u32 chip_name = viapar->shared->chip_info.gfx_chip_name;
 309
 310        engine = viapar->shared->vdev->engine_mmio;
 311        if (!engine) {
 312                printk(KERN_WARNING "viafb_init_accel: ioremap failed, "
 313                        "hardware acceleration disabled\n");
 314                return -ENOMEM;
 315        }
 316
 317        switch (chip_name) {
 318        case UNICHROME_CLE266:
 319        case UNICHROME_K400:
 320        case UNICHROME_K800:
 321        case UNICHROME_PM800:
 322        case UNICHROME_CN700:
 323        case UNICHROME_CX700:
 324        case UNICHROME_CN750:
 325        case UNICHROME_K8M890:
 326        case UNICHROME_P4M890:
 327        case UNICHROME_P4M900:
 328                viapar->shared->hw_bitblt = hw_bitblt_1;
 329                break;
 330        case UNICHROME_VX800:
 331        case UNICHROME_VX855:
 332        case UNICHROME_VX900:
 333                viapar->shared->hw_bitblt = hw_bitblt_2;
 334                break;
 335        default:
 336                viapar->shared->hw_bitblt = NULL;
 337        }
 338
 339        viapar->fbmem_free -= CURSOR_SIZE;
 340        viapar->shared->cursor_vram_addr = viapar->fbmem_free;
 341        viapar->fbmem_used += CURSOR_SIZE;
 342
 343        viapar->fbmem_free -= VQ_SIZE;
 344        viapar->shared->vq_vram_addr = viapar->fbmem_free;
 345        viapar->fbmem_used += VQ_SIZE;
 346
 347#if IS_ENABLED(CONFIG_VIDEO_VIA_CAMERA)
 348        /*
 349         * Set aside a chunk of framebuffer memory for the camera
 350         * driver.  Someday this driver probably needs a proper allocator
 351         * for fbmem; for now, we just have to do this before the
 352         * framebuffer initializes itself.
 353         *
 354         * As for the size: the engine can handle three frames,
 355         * 16 bits deep, up to VGA resolution.
 356         */
 357        viapar->shared->vdev->camera_fbmem_size = 3*VGA_HEIGHT*VGA_WIDTH*2;
 358        viapar->fbmem_free -= viapar->shared->vdev->camera_fbmem_size;
 359        viapar->fbmem_used += viapar->shared->vdev->camera_fbmem_size;
 360        viapar->shared->vdev->camera_fbmem_offset = viapar->fbmem_free;
 361#endif
 362
 363        viafb_reset_engine(viapar);
 364        return 0;
 365}
 366
 367void viafb_reset_engine(struct viafb_par *viapar)
 368{
 369        void __iomem *engine = viapar->shared->vdev->engine_mmio;
 370        int highest_reg, i;
 371        u32 vq_start_addr, vq_end_addr, vq_start_low, vq_end_low, vq_high,
 372                vq_len, chip_name = viapar->shared->chip_info.gfx_chip_name;
 373
 374        /* Initialize registers to reset the 2D engine */
 375        switch (viapar->shared->chip_info.twod_engine) {
 376        case VIA_2D_ENG_M1:
 377                highest_reg = 0x5c;
 378                break;
 379        default:
 380                highest_reg = 0x40;
 381                break;
 382        }
 383        for (i = 0; i <= highest_reg; i += 4)
 384                writel(0x0, engine + i);
 385
 386        /* Init AGP and VQ regs */
 387        switch (chip_name) {
 388        case UNICHROME_K8M890:
 389        case UNICHROME_P4M900:
 390        case UNICHROME_VX800:
 391        case UNICHROME_VX855:
 392        case UNICHROME_VX900:
 393                writel(0x00100000, engine + VIA_REG_CR_TRANSET);
 394                writel(0x680A0000, engine + VIA_REG_CR_TRANSPACE);
 395                writel(0x02000000, engine + VIA_REG_CR_TRANSPACE);
 396                break;
 397
 398        default:
 399                writel(0x00100000, engine + VIA_REG_TRANSET);
 400                writel(0x00000000, engine + VIA_REG_TRANSPACE);
 401                writel(0x00333004, engine + VIA_REG_TRANSPACE);
 402                writel(0x60000000, engine + VIA_REG_TRANSPACE);
 403                writel(0x61000000, engine + VIA_REG_TRANSPACE);
 404                writel(0x62000000, engine + VIA_REG_TRANSPACE);
 405                writel(0x63000000, engine + VIA_REG_TRANSPACE);
 406                writel(0x64000000, engine + VIA_REG_TRANSPACE);
 407                writel(0x7D000000, engine + VIA_REG_TRANSPACE);
 408
 409                writel(0xFE020000, engine + VIA_REG_TRANSET);
 410                writel(0x00000000, engine + VIA_REG_TRANSPACE);
 411                break;
 412        }
 413
 414        /* Enable VQ */
 415        vq_start_addr = viapar->shared->vq_vram_addr;
 416        vq_end_addr = viapar->shared->vq_vram_addr + VQ_SIZE - 1;
 417
 418        vq_start_low = 0x50000000 | (vq_start_addr & 0xFFFFFF);
 419        vq_end_low = 0x51000000 | (vq_end_addr & 0xFFFFFF);
 420        vq_high = 0x52000000 | ((vq_start_addr & 0xFF000000) >> 24) |
 421                ((vq_end_addr & 0xFF000000) >> 16);
 422        vq_len = 0x53000000 | (VQ_SIZE >> 3);
 423
 424        switch (chip_name) {
 425        case UNICHROME_K8M890:
 426        case UNICHROME_P4M900:
 427        case UNICHROME_VX800:
 428        case UNICHROME_VX855:
 429        case UNICHROME_VX900:
 430                vq_start_low |= 0x20000000;
 431                vq_end_low |= 0x20000000;
 432                vq_high |= 0x20000000;
 433                vq_len |= 0x20000000;
 434
 435                writel(0x00100000, engine + VIA_REG_CR_TRANSET);
 436                writel(vq_high, engine + VIA_REG_CR_TRANSPACE);
 437                writel(vq_start_low, engine + VIA_REG_CR_TRANSPACE);
 438                writel(vq_end_low, engine + VIA_REG_CR_TRANSPACE);
 439                writel(vq_len, engine + VIA_REG_CR_TRANSPACE);
 440                writel(0x74301001, engine + VIA_REG_CR_TRANSPACE);
 441                writel(0x00000000, engine + VIA_REG_CR_TRANSPACE);
 442                break;
 443        default:
 444                writel(0x00FE0000, engine + VIA_REG_TRANSET);
 445                writel(0x080003FE, engine + VIA_REG_TRANSPACE);
 446                writel(0x0A00027C, engine + VIA_REG_TRANSPACE);
 447                writel(0x0B000260, engine + VIA_REG_TRANSPACE);
 448                writel(0x0C000274, engine + VIA_REG_TRANSPACE);
 449                writel(0x0D000264, engine + VIA_REG_TRANSPACE);
 450                writel(0x0E000000, engine + VIA_REG_TRANSPACE);
 451                writel(0x0F000020, engine + VIA_REG_TRANSPACE);
 452                writel(0x1000027E, engine + VIA_REG_TRANSPACE);
 453                writel(0x110002FE, engine + VIA_REG_TRANSPACE);
 454                writel(0x200F0060, engine + VIA_REG_TRANSPACE);
 455
 456                writel(0x00000006, engine + VIA_REG_TRANSPACE);
 457                writel(0x40008C0F, engine + VIA_REG_TRANSPACE);
 458                writel(0x44000000, engine + VIA_REG_TRANSPACE);
 459                writel(0x45080C04, engine + VIA_REG_TRANSPACE);
 460                writel(0x46800408, engine + VIA_REG_TRANSPACE);
 461
 462                writel(vq_high, engine + VIA_REG_TRANSPACE);
 463                writel(vq_start_low, engine + VIA_REG_TRANSPACE);
 464                writel(vq_end_low, engine + VIA_REG_TRANSPACE);
 465                writel(vq_len, engine + VIA_REG_TRANSPACE);
 466                break;
 467        }
 468
 469        /* Set Cursor Image Base Address */
 470        writel(viapar->shared->cursor_vram_addr, engine + VIA_REG_CURSOR_MODE);
 471        writel(0x0, engine + VIA_REG_CURSOR_POS);
 472        writel(0x0, engine + VIA_REG_CURSOR_ORG);
 473        writel(0x0, engine + VIA_REG_CURSOR_BG);
 474        writel(0x0, engine + VIA_REG_CURSOR_FG);
 475        return;
 476}
 477
 478void viafb_show_hw_cursor(struct fb_info *info, int Status)
 479{
 480        struct viafb_par *viapar = info->par;
 481        u32 temp, iga_path = viapar->iga_path;
 482
 483        temp = readl(viapar->shared->vdev->engine_mmio + VIA_REG_CURSOR_MODE);
 484        switch (Status) {
 485        case HW_Cursor_ON:
 486                temp |= 0x1;
 487                break;
 488        case HW_Cursor_OFF:
 489                temp &= 0xFFFFFFFE;
 490                break;
 491        }
 492        switch (iga_path) {
 493        case IGA2:
 494                temp |= 0x80000000;
 495                break;
 496        case IGA1:
 497        default:
 498                temp &= 0x7FFFFFFF;
 499        }
 500        writel(temp, viapar->shared->vdev->engine_mmio + VIA_REG_CURSOR_MODE);
 501}
 502
 503void viafb_wait_engine_idle(struct fb_info *info)
 504{
 505        struct viafb_par *viapar = info->par;
 506        int loop = 0;
 507        u32 mask;
 508        void __iomem *engine = viapar->shared->vdev->engine_mmio;
 509
 510        switch (viapar->shared->chip_info.twod_engine) {
 511        case VIA_2D_ENG_H5:
 512        case VIA_2D_ENG_M1:
 513                mask = VIA_CMD_RGTR_BUSY_M1 | VIA_2D_ENG_BUSY_M1 |
 514                              VIA_3D_ENG_BUSY_M1;
 515                break;
 516        default:
 517                while (!(readl(engine + VIA_REG_STATUS) &
 518                                VIA_VR_QUEUE_BUSY) && (loop < MAXLOOP)) {
 519                        loop++;
 520                        cpu_relax();
 521                }
 522                mask = VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | VIA_3D_ENG_BUSY;
 523                break;
 524        }
 525
 526        while ((readl(engine + VIA_REG_STATUS) & mask) && (loop < MAXLOOP)) {
 527                loop++;
 528                cpu_relax();
 529        }
 530
 531        if (loop >= MAXLOOP)
 532                printk(KERN_ERR "viafb_wait_engine_idle: not syncing\n");
 533}
 534