accel.c (14042B)
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}