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