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 "global.h"
  22
  23static int hw_bitblt_1(void __iomem *engine, u8 op, u32 width, u32 height,
  24        u8 dst_bpp, u32 dst_addr, u32 dst_pitch, u32 dst_x, u32 dst_y,
  25        u32 *src_mem, u32 src_addr, u32 src_pitch, u32 src_x, u32 src_y,
  26        u32 fg_color, u32 bg_color, u8 fill_rop)
  27{
  28        u32 ge_cmd = 0, tmp, i;
  29
  30        if (!op || op > 3) {
  31                printk(KERN_WARNING "hw_bitblt_1: Invalid operation: %d\n", op);
  32                return -EINVAL;
  33        }
  34
  35        if (op != VIA_BITBLT_FILL && !src_mem && src_addr == dst_addr) {
  36                if (src_x < dst_x) {
  37                        ge_cmd |= 0x00008000;
  38                        src_x += width - 1;
  39                        dst_x += width - 1;
  40                }
  41                if (src_y < dst_y) {
  42                        ge_cmd |= 0x00004000;
  43                        src_y += height - 1;
  44                        dst_y += height - 1;
  45                }
  46        }
  47
  48        if (op == VIA_BITBLT_FILL) {
  49                switch (fill_rop) {
  50                case 0x00: /* blackness */
  51                case 0x5A: /* pattern inversion */
  52                case 0xF0: /* pattern copy */
  53                case 0xFF: /* whiteness */
  54                        break;
  55                default:
  56                        printk(KERN_WARNING "hw_bitblt_1: Invalid fill rop: "
  57                                "%u\n", fill_rop);
  58                        return -EINVAL;
  59                }
  60        }
  61
  62        switch (dst_bpp) {
  63        case 8:
  64                tmp = 0x00000000;
  65                break;
  66        case 16:
  67                tmp = 0x00000100;
  68                break;
  69        case 32:
  70                tmp = 0x00000300;
  71                break;
  72        default:
  73                printk(KERN_WARNING "hw_bitblt_1: Unsupported bpp %d\n",
  74                        dst_bpp);
  75                return -EINVAL;
  76        }
  77        writel(tmp, engine + 0x04);
  78
  79        if (op != VIA_BITBLT_FILL) {
  80                if (src_x & (op == VIA_BITBLT_MONO ? 0xFFFF8000 : 0xFFFFF000)
  81                        || src_y & 0xFFFFF000) {
  82                        printk(KERN_WARNING "hw_bitblt_1: Unsupported source "
  83                                "x/y %d %d\n", src_x, src_y);
  84                        return -EINVAL;
  85                }
  86                tmp = src_x | (src_y << 16);
  87                writel(tmp, engine + 0x08);
  88        }
  89
  90        if (dst_x & 0xFFFFF000 || dst_y & 0xFFFFF000) {
  91                printk(KERN_WARNING "hw_bitblt_1: Unsupported destination x/y "
  92                        "%d %d\n", dst_x, dst_y);
  93                return -EINVAL;
  94        }
  95        tmp = dst_x | (dst_y << 16);
  96        writel(tmp, engine + 0x0C);
  97
  98        if ((width - 1) & 0xFFFFF000 || (height - 1) & 0xFFFFF000) {
  99                printk(KERN_WARNING "hw_bitblt_1: Unsupported width/height "
 100                        "%d %d\n", width, height);
 101                return -EINVAL;
 102        }
 103        tmp = (width - 1) | ((height - 1) << 16);
 104        writel(tmp, engine + 0x10);
 105
 106        if (op != VIA_BITBLT_COLOR)
 107                writel(fg_color, engine + 0x18);
 108
 109        if (op == VIA_BITBLT_MONO)
 110                writel(bg_color, engine + 0x1C);
 111
 112        if (op != VIA_BITBLT_FILL) {
 113                tmp = src_mem ? 0 : src_addr;
 114                if (dst_addr & 0xE0000007) {
 115                        printk(KERN_WARNING "hw_bitblt_1: Unsupported source "
 116                                "address %X\n", tmp);
 117                        return -EINVAL;
 118                }
 119                tmp >>= 3;
 120                writel(tmp, engine + 0x30);
 121        }
 122
 123        if (dst_addr & 0xE0000007) {
 124                printk(KERN_WARNING "hw_bitblt_1: Unsupported destination "
 125                        "address %X\n", dst_addr);
 126                return -EINVAL;
 127        }
 128        tmp = dst_addr >> 3;
 129        writel(tmp, engine + 0x34);
 130
 131        if (op == VIA_BITBLT_FILL)
 132                tmp = 0;
 133        else
 134                tmp = src_pitch;
 135        if (tmp & 0xFFFFC007 || dst_pitch & 0xFFFFC007) {
 136                printk(KERN_WARNING "hw_bitblt_1: Unsupported pitch %X %X\n",
 137                        tmp, dst_pitch);
 138                return -EINVAL;
 139        }
 140        tmp = (tmp >> 3) | (dst_pitch << (16 - 3));
 141        writel(tmp, engine + 0x38);
 142
 143        if (op == VIA_BITBLT_FILL)
 144                ge_cmd |= fill_rop << 24 | 0x00002000 | 0x00000001;
 145        else {
 146                ge_cmd |= 0xCC000000; /* ROP=SRCCOPY */
 147                if (src_mem)
 148                        ge_cmd |= 0x00000040;
 149                if (op == VIA_BITBLT_MONO)
 150                        ge_cmd |= 0x00000002 | 0x00000100 | 0x00020000;
 151                else
 152                        ge_cmd |= 0x00000001;
 153        }
 154        writel(ge_cmd, engine);
 155
 156        if (op == VIA_BITBLT_FILL || !src_mem)
 157                return 0;
 158
 159        tmp = (width * height * (op == VIA_BITBLT_MONO ? 1 : (dst_bpp >> 3)) +
 160                3) >> 2;
 161
 162        for (i = 0; i < tmp; i++)
 163                writel(src_mem[i], engine + VIA_MMIO_BLTBASE);
 164
 165        return 0;
 166}
 167
 168static int hw_bitblt_2(void __iomem *engine, u8 op, u32 width, u32 height,
 169        u8 dst_bpp, u32 dst_addr, u32 dst_pitch, u32 dst_x, u32 dst_y,
 170        u32 *src_mem, u32 src_addr, u32 src_pitch, u32 src_x, u32 src_y,
 171        u32 fg_color, u32 bg_color, u8 fill_rop)
 172{
 173        u32 ge_cmd = 0, tmp, i;
 174
 175        if (!op || op > 3) {
 176                printk(KERN_WARNING "hw_bitblt_2: Invalid operation: %d\n", op);
 177                return -EINVAL;
 178        }
 179
 180        if (op != VIA_BITBLT_FILL && !src_mem && src_addr == dst_addr) {
 181                if (src_x < dst_x) {
 182                        ge_cmd |= 0x00008000;
 183                        src_x += width - 1;
 184                        dst_x += width - 1;
 185                }
 186                if (src_y < dst_y) {
 187                        ge_cmd |= 0x00004000;
 188                        src_y += height - 1;
 189                        dst_y += height - 1;
 190                }
 191        }
 192
 193        if (op == VIA_BITBLT_FILL) {
 194                switch (fill_rop) {
 195                case 0x00: /* blackness */
 196                case 0x5A: /* pattern inversion */
 197                case 0xF0: /* pattern copy */
 198                case 0xFF: /* whiteness */
 199                        break;
 200                default:
 201                        printk(KERN_WARNING "hw_bitblt_2: Invalid fill rop: "
 202                                "%u\n", fill_rop);
 203                        return -EINVAL;
 204                }
 205        }
 206
 207        switch (dst_bpp) {
 208        case 8:
 209                tmp = 0x00000000;
 210                break;
 211        case 16:
 212                tmp = 0x00000100;
 213                break;
 214        case 32:
 215                tmp = 0x00000300;
 216                break;
 217        default:
 218                printk(KERN_WARNING "hw_bitblt_2: Unsupported bpp %d\n",
 219                        dst_bpp);
 220                return -EINVAL;
 221        }
 222        writel(tmp, engine + 0x04);
 223
 224        if (op == VIA_BITBLT_FILL)
 225                tmp = 0;
 226        else
 227                tmp = src_pitch;
 228        if (tmp & 0xFFFFC007 || dst_pitch & 0xFFFFC007) {
 229                printk(KERN_WARNING "hw_bitblt_2: Unsupported pitch %X %X\n",
 230                        tmp, dst_pitch);
 231                return -EINVAL;
 232        }
 233        tmp = (tmp >> 3) | (dst_pitch << (16 - 3));
 234        writel(tmp, engine + 0x08);
 235
 236        if ((width - 1) & 0xFFFFF000 || (height - 1) & 0xFFFFF000) {
 237                printk(KERN_WARNING "hw_bitblt_2: Unsupported width/height "
 238                        "%d %d\n", width, height);
 239                return -EINVAL;
 240        }
 241        tmp = (width - 1) | ((height - 1) << 16);
 242        writel(tmp, engine + 0x0C);
 243
 244        if (dst_x & 0xFFFFF000 || dst_y & 0xFFFFF000) {
 245                printk(KERN_WARNING "hw_bitblt_2: Unsupported destination x/y "
 246                        "%d %d\n", dst_x, dst_y);
 247                return -EINVAL;
 248        }
 249        tmp = dst_x | (dst_y << 16);
 250        writel(tmp, engine + 0x10);
 251
 252        if (dst_addr & 0xE0000007) {
 253                printk(KERN_WARNING "hw_bitblt_2: Unsupported destination "
 254                        "address %X\n", dst_addr);
 255                return -EINVAL;
 256        }
 257        tmp = dst_addr >> 3;
 258        writel(tmp, engine + 0x14);
 259
 260        if (op != VIA_BITBLT_FILL) {
 261                if (src_x & (op == VIA_BITBLT_MONO ? 0xFFFF8000 : 0xFFFFF000)
 262                        || src_y & 0xFFFFF000) {
 263                        printk(KERN_WARNING "hw_bitblt_2: Unsupported source "
 264                                "x/y %d %d\n", src_x, src_y);
 265                        return -EINVAL;
 266                }
 267                tmp = src_x | (src_y << 16);
 268                writel(tmp, engine + 0x18);
 269
 270                tmp = src_mem ? 0 : src_addr;
 271                if (dst_addr & 0xE0000007) {
 272                        printk(KERN_WARNING "hw_bitblt_2: Unsupported source "
 273                                "address %X\n", tmp);
 274                        return -EINVAL;
 275                }
 276                tmp >>= 3;
 277                writel(tmp, engine + 0x1C);
 278        }
 279
 280        if (op != VIA_BITBLT_COLOR)
 281                writel(fg_color, engine + 0x4C);
 282
 283        if (op == VIA_BITBLT_MONO)
 284                writel(bg_color, engine + 0x50);
 285
 286        if (op == VIA_BITBLT_FILL)
 287                ge_cmd |= fill_rop << 24 | 0x00002000 | 0x00000001;
 288        else {
 289                ge_cmd |= 0xCC000000; /* ROP=SRCCOPY */
 290                if (src_mem)
 291                        ge_cmd |= 0x00000040;
 292                if (op == VIA_BITBLT_MONO)
 293                        ge_cmd |= 0x00000002 | 0x00000100 | 0x00020000;
 294                else
 295                        ge_cmd |= 0x00000001;
 296        }
 297        writel(ge_cmd, engine);
 298
 299        if (op == VIA_BITBLT_FILL || !src_mem)
 300                return 0;
 301
 302        tmp = (width * height * (op == VIA_BITBLT_MONO ? 1 : (dst_bpp >> 3)) +
 303                3) >> 2;
 304
 305        for (i = 0; i < tmp; i++)
 306                writel(src_mem[i], engine + VIA_MMIO_BLTBASE);
 307
 308        return 0;
 309}
 310
 311int viafb_init_engine(struct fb_info *info)
 312{
 313        struct viafb_par *viapar = info->par;
 314        void __iomem *engine;
 315        u32 vq_start_addr, vq_end_addr, vq_start_low, vq_end_low, vq_high,
 316                vq_len, chip_name = viapar->shared->chip_info.gfx_chip_name;
 317
 318        engine = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len);
 319        viapar->shared->engine_mmio = engine;
 320        if (!engine) {
 321                printk(KERN_WARNING "viafb_init_accel: ioremap failed, "
 322                        "hardware acceleration disabled\n");
 323                return -ENOMEM;
 324        }
 325
 326        switch (chip_name) {
 327        case UNICHROME_CLE266:
 328        case UNICHROME_K400:
 329        case UNICHROME_K800:
 330        case UNICHROME_PM800:
 331        case UNICHROME_CN700:
 332        case UNICHROME_CX700:
 333        case UNICHROME_CN750:
 334        case UNICHROME_K8M890:
 335        case UNICHROME_P4M890:
 336        case UNICHROME_P4M900:
 337                viapar->shared->hw_bitblt = hw_bitblt_1;
 338                break;
 339        case UNICHROME_VX800:
 340        case UNICHROME_VX855:
 341                viapar->shared->hw_bitblt = hw_bitblt_2;
 342                break;
 343        default:
 344                viapar->shared->hw_bitblt = NULL;
 345        }
 346
 347        viapar->fbmem_free -= CURSOR_SIZE;
 348        viapar->shared->cursor_vram_addr = viapar->fbmem_free;
 349        viapar->fbmem_used += CURSOR_SIZE;
 350
 351        viapar->fbmem_free -= VQ_SIZE;
 352        viapar->shared->vq_vram_addr = viapar->fbmem_free;
 353        viapar->fbmem_used += VQ_SIZE;
 354
 355        /* Init AGP and VQ regs */
 356        switch (chip_name) {
 357        case UNICHROME_K8M890:
 358        case UNICHROME_P4M900:
 359                writel(0x00100000, engine + VIA_REG_CR_TRANSET);
 360                writel(0x680A0000, engine + VIA_REG_CR_TRANSPACE);
 361                writel(0x02000000, engine + VIA_REG_CR_TRANSPACE);
 362                break;
 363
 364        default:
 365                writel(0x00100000, engine + VIA_REG_TRANSET);
 366                writel(0x00000000, engine + VIA_REG_TRANSPACE);
 367                writel(0x00333004, engine + VIA_REG_TRANSPACE);
 368                writel(0x60000000, engine + VIA_REG_TRANSPACE);
 369                writel(0x61000000, engine + VIA_REG_TRANSPACE);
 370                writel(0x62000000, engine + VIA_REG_TRANSPACE);
 371                writel(0x63000000, engine + VIA_REG_TRANSPACE);
 372                writel(0x64000000, engine + VIA_REG_TRANSPACE);
 373                writel(0x7D000000, engine + VIA_REG_TRANSPACE);
 374
 375                writel(0xFE020000, engine + VIA_REG_TRANSET);
 376                writel(0x00000000, engine + VIA_REG_TRANSPACE);
 377                break;
 378        }
 379
 380        /* Enable VQ */
 381        vq_start_addr = viapar->shared->vq_vram_addr;
 382        vq_end_addr = viapar->shared->vq_vram_addr + VQ_SIZE - 1;
 383
 384        vq_start_low = 0x50000000 | (vq_start_addr & 0xFFFFFF);
 385        vq_end_low = 0x51000000 | (vq_end_addr & 0xFFFFFF);
 386        vq_high = 0x52000000 | ((vq_start_addr & 0xFF000000) >> 24) |
 387                ((vq_end_addr & 0xFF000000) >> 16);
 388        vq_len = 0x53000000 | (VQ_SIZE >> 3);
 389
 390        switch (chip_name) {
 391        case UNICHROME_K8M890:
 392        case UNICHROME_P4M900:
 393                vq_start_low |= 0x20000000;
 394                vq_end_low |= 0x20000000;
 395                vq_high |= 0x20000000;
 396                vq_len |= 0x20000000;
 397
 398                writel(0x00100000, engine + VIA_REG_CR_TRANSET);
 399                writel(vq_high, engine + VIA_REG_CR_TRANSPACE);
 400                writel(vq_start_low, engine + VIA_REG_CR_TRANSPACE);
 401                writel(vq_end_low, engine + VIA_REG_CR_TRANSPACE);
 402                writel(vq_len, engine + VIA_REG_CR_TRANSPACE);
 403                writel(0x74301001, engine + VIA_REG_CR_TRANSPACE);
 404                writel(0x00000000, engine + VIA_REG_CR_TRANSPACE);
 405                break;
 406        default:
 407                writel(0x00FE0000, engine + VIA_REG_TRANSET);
 408                writel(0x080003FE, engine + VIA_REG_TRANSPACE);
 409                writel(0x0A00027C, engine + VIA_REG_TRANSPACE);
 410                writel(0x0B000260, engine + VIA_REG_TRANSPACE);
 411                writel(0x0C000274, engine + VIA_REG_TRANSPACE);
 412                writel(0x0D000264, engine + VIA_REG_TRANSPACE);
 413                writel(0x0E000000, engine + VIA_REG_TRANSPACE);
 414                writel(0x0F000020, engine + VIA_REG_TRANSPACE);
 415                writel(0x1000027E, engine + VIA_REG_TRANSPACE);
 416                writel(0x110002FE, engine + VIA_REG_TRANSPACE);
 417                writel(0x200F0060, engine + VIA_REG_TRANSPACE);
 418
 419                writel(0x00000006, engine + VIA_REG_TRANSPACE);
 420                writel(0x40008C0F, engine + VIA_REG_TRANSPACE);
 421                writel(0x44000000, engine + VIA_REG_TRANSPACE);
 422                writel(0x45080C04, engine + VIA_REG_TRANSPACE);
 423                writel(0x46800408, engine + VIA_REG_TRANSPACE);
 424
 425                writel(vq_high, engine + VIA_REG_TRANSPACE);
 426                writel(vq_start_low, engine + VIA_REG_TRANSPACE);
 427                writel(vq_end_low, engine + VIA_REG_TRANSPACE);
 428                writel(vq_len, engine + VIA_REG_TRANSPACE);
 429                break;
 430        }
 431
 432        /* Set Cursor Image Base Address */
 433        writel(viapar->shared->cursor_vram_addr, engine + VIA_REG_CURSOR_MODE);
 434        writel(0x0, engine + VIA_REG_CURSOR_POS);
 435        writel(0x0, engine + VIA_REG_CURSOR_ORG);
 436        writel(0x0, engine + VIA_REG_CURSOR_BG);
 437        writel(0x0, engine + VIA_REG_CURSOR_FG);
 438        return 0;
 439}
 440
 441void viafb_show_hw_cursor(struct fb_info *info, int Status)
 442{
 443        struct viafb_par *viapar = info->par;
 444        u32 temp, iga_path = viapar->iga_path;
 445
 446        temp = readl(viapar->shared->engine_mmio + VIA_REG_CURSOR_MODE);
 447        switch (Status) {
 448        case HW_Cursor_ON:
 449                temp |= 0x1;
 450                break;
 451        case HW_Cursor_OFF:
 452                temp &= 0xFFFFFFFE;
 453                break;
 454        }
 455        switch (iga_path) {
 456        case IGA2:
 457                temp |= 0x80000000;
 458                break;
 459        case IGA1:
 460        default:
 461                temp &= 0x7FFFFFFF;
 462        }
 463        writel(temp, viapar->shared->engine_mmio + VIA_REG_CURSOR_MODE);
 464}
 465
 466void viafb_wait_engine_idle(struct fb_info *info)
 467{
 468        struct viafb_par *viapar = info->par;
 469        int loop = 0;
 470
 471        while (!(readl(viapar->shared->engine_mmio + VIA_REG_STATUS) &
 472                        VIA_VR_QUEUE_BUSY) && (loop < MAXLOOP)) {
 473                loop++;
 474                cpu_relax();
 475        }
 476
 477        while ((readl(viapar->shared->engine_mmio + VIA_REG_STATUS) &
 478                    (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | VIA_3D_ENG_BUSY)) &&
 479                    (loop < MAXLOOP)) {
 480                loop++;
 481                cpu_relax();
 482        }
 483
 484        if (loop >= MAXLOOP)
 485                printk(KERN_ERR "viafb_wait_engine_idle: not syncing\n");
 486}
 487