534 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*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 (tmp & 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 else138 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 else156 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 else219 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 (tmp & 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 else288 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 camera350 * driver. Someday this driver probably needs a proper allocator351 * for fbmem; for now, we just have to do this before the352 * 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#endif362 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}534