root/drivers/video/fbdev/via/accel.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. viafb_set_bpp
  2. hw_bitblt_1
  3. hw_bitblt_2
  4. viafb_setup_engine
  5. viafb_reset_engine
  6. viafb_show_hw_cursor
  7. viafb_wait_engine_idle

   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  */
  13 static 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 
  39 static 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 
 172 static 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 
 304 int 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 
 367 void 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 
 478 void 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 
 503 void 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 }

/* [<][>][^][v][top][bottom][index][help] */