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