accel.c revision 31de59d5e1cd6968ea9d1a19cceefb7a037e46bf
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 viapar->shared->hw_bitblt = hw_bitblt_2; 341 break; 342 default: 343 viapar->shared->hw_bitblt = NULL; 344 } 345 346 viapar->fbmem_free -= CURSOR_SIZE; 347 viapar->shared->cursor_vram_addr = viapar->fbmem_free; 348 viapar->fbmem_used += CURSOR_SIZE; 349 350 viapar->fbmem_free -= VQ_SIZE; 351 viapar->shared->vq_vram_addr = viapar->fbmem_free; 352 viapar->fbmem_used += VQ_SIZE; 353 354 /* Init AGP and VQ regs */ 355 switch (chip_name) { 356 case UNICHROME_K8M890: 357 case UNICHROME_P4M900: 358 writel(0x00100000, engine + VIA_REG_CR_TRANSET); 359 writel(0x680A0000, engine + VIA_REG_CR_TRANSPACE); 360 writel(0x02000000, engine + VIA_REG_CR_TRANSPACE); 361 break; 362 363 default: 364 writel(0x00100000, engine + VIA_REG_TRANSET); 365 writel(0x00000000, engine + VIA_REG_TRANSPACE); 366 writel(0x00333004, engine + VIA_REG_TRANSPACE); 367 writel(0x60000000, engine + VIA_REG_TRANSPACE); 368 writel(0x61000000, engine + VIA_REG_TRANSPACE); 369 writel(0x62000000, engine + VIA_REG_TRANSPACE); 370 writel(0x63000000, engine + VIA_REG_TRANSPACE); 371 writel(0x64000000, engine + VIA_REG_TRANSPACE); 372 writel(0x7D000000, engine + VIA_REG_TRANSPACE); 373 374 writel(0xFE020000, engine + VIA_REG_TRANSET); 375 writel(0x00000000, engine + VIA_REG_TRANSPACE); 376 break; 377 } 378 379 /* Enable VQ */ 380 vq_start_addr = viapar->shared->vq_vram_addr; 381 vq_end_addr = viapar->shared->vq_vram_addr + VQ_SIZE - 1; 382 383 vq_start_low = 0x50000000 | (vq_start_addr & 0xFFFFFF); 384 vq_end_low = 0x51000000 | (vq_end_addr & 0xFFFFFF); 385 vq_high = 0x52000000 | ((vq_start_addr & 0xFF000000) >> 24) | 386 ((vq_end_addr & 0xFF000000) >> 16); 387 vq_len = 0x53000000 | (VQ_SIZE >> 3); 388 389 switch (chip_name) { 390 case UNICHROME_K8M890: 391 case UNICHROME_P4M900: 392 vq_start_low |= 0x20000000; 393 vq_end_low |= 0x20000000; 394 vq_high |= 0x20000000; 395 vq_len |= 0x20000000; 396 397 writel(0x00100000, engine + VIA_REG_CR_TRANSET); 398 writel(vq_high, engine + VIA_REG_CR_TRANSPACE); 399 writel(vq_start_low, engine + VIA_REG_CR_TRANSPACE); 400 writel(vq_end_low, engine + VIA_REG_CR_TRANSPACE); 401 writel(vq_len, engine + VIA_REG_CR_TRANSPACE); 402 writel(0x74301001, engine + VIA_REG_CR_TRANSPACE); 403 writel(0x00000000, engine + VIA_REG_CR_TRANSPACE); 404 break; 405 default: 406 writel(0x00FE0000, engine + VIA_REG_TRANSET); 407 writel(0x080003FE, engine + VIA_REG_TRANSPACE); 408 writel(0x0A00027C, engine + VIA_REG_TRANSPACE); 409 writel(0x0B000260, engine + VIA_REG_TRANSPACE); 410 writel(0x0C000274, engine + VIA_REG_TRANSPACE); 411 writel(0x0D000264, engine + VIA_REG_TRANSPACE); 412 writel(0x0E000000, engine + VIA_REG_TRANSPACE); 413 writel(0x0F000020, engine + VIA_REG_TRANSPACE); 414 writel(0x1000027E, engine + VIA_REG_TRANSPACE); 415 writel(0x110002FE, engine + VIA_REG_TRANSPACE); 416 writel(0x200F0060, engine + VIA_REG_TRANSPACE); 417 418 writel(0x00000006, engine + VIA_REG_TRANSPACE); 419 writel(0x40008C0F, engine + VIA_REG_TRANSPACE); 420 writel(0x44000000, engine + VIA_REG_TRANSPACE); 421 writel(0x45080C04, engine + VIA_REG_TRANSPACE); 422 writel(0x46800408, engine + VIA_REG_TRANSPACE); 423 424 writel(vq_high, engine + VIA_REG_TRANSPACE); 425 writel(vq_start_low, engine + VIA_REG_TRANSPACE); 426 writel(vq_end_low, engine + VIA_REG_TRANSPACE); 427 writel(vq_len, engine + VIA_REG_TRANSPACE); 428 break; 429 } 430 431 /* Set Cursor Image Base Address */ 432 writel(viapar->shared->cursor_vram_addr, engine + VIA_REG_CURSOR_MODE); 433 writel(0x0, engine + VIA_REG_CURSOR_POS); 434 writel(0x0, engine + VIA_REG_CURSOR_ORG); 435 writel(0x0, engine + VIA_REG_CURSOR_BG); 436 writel(0x0, engine + VIA_REG_CURSOR_FG); 437 return 0; 438} 439 440void viafb_show_hw_cursor(struct fb_info *info, int Status) 441{ 442 struct viafb_par *viapar = info->par; 443 u32 temp, iga_path = viapar->iga_path; 444 445 temp = readl(viapar->shared->engine_mmio + VIA_REG_CURSOR_MODE); 446 switch (Status) { 447 case HW_Cursor_ON: 448 temp |= 0x1; 449 break; 450 case HW_Cursor_OFF: 451 temp &= 0xFFFFFFFE; 452 break; 453 } 454 switch (iga_path) { 455 case IGA2: 456 temp |= 0x80000000; 457 break; 458 case IGA1: 459 default: 460 temp &= 0x7FFFFFFF; 461 } 462 writel(temp, viapar->shared->engine_mmio + VIA_REG_CURSOR_MODE); 463} 464 465void viafb_wait_engine_idle(struct fb_info *info) 466{ 467 struct viafb_par *viapar = info->par; 468 int loop = 0; 469 470 while (!(readl(viapar->shared->engine_mmio + VIA_REG_STATUS) & 471 VIA_VR_QUEUE_BUSY) && (loop < MAXLOOP)) { 472 loop++; 473 cpu_relax(); 474 } 475 476 while ((readl(viapar->shared->engine_mmio + VIA_REG_STATUS) & 477 (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | VIA_3D_ENG_BUSY)) && 478 (loop < MAXLOOP)) { 479 loop++; 480 cpu_relax(); 481 } 482 483 if (loop >= MAXLOOP) 484 printk(KERN_ERR "viafb_wait_engine_idle: not syncing\n"); 485} 486