Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
0004  * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
0005 
0006  */
0007 #include <linux/via-core.h>
0008 #include "global.h"
0009 
0010 /*
0011  * Figure out an appropriate bytes-per-pixel setting.
0012  */
0013 static int viafb_set_bpp(void __iomem *engine, u8 bpp)
0014 {
0015     u32 gemode;
0016 
0017     /* Preserve the reserved bits */
0018     /* Lowest 2 bits to zero gives us no rotation */
0019     gemode = readl(engine + VIA_REG_GEMODE) & 0xfffffcfc;
0020     switch (bpp) {
0021     case 8:
0022         gemode |= VIA_GEM_8bpp;
0023         break;
0024     case 16:
0025         gemode |= VIA_GEM_16bpp;
0026         break;
0027     case 32:
0028         gemode |= VIA_GEM_32bpp;
0029         break;
0030     default:
0031         printk(KERN_WARNING "viafb_set_bpp: Unsupported bpp %d\n", bpp);
0032         return -EINVAL;
0033     }
0034     writel(gemode, engine + VIA_REG_GEMODE);
0035     return 0;
0036 }
0037 
0038 
0039 static int hw_bitblt_1(void __iomem *engine, u8 op, u32 width, u32 height,
0040     u8 dst_bpp, u32 dst_addr, u32 dst_pitch, u32 dst_x, u32 dst_y,
0041     u32 *src_mem, u32 src_addr, u32 src_pitch, u32 src_x, u32 src_y,
0042     u32 fg_color, u32 bg_color, u8 fill_rop)
0043 {
0044     u32 ge_cmd = 0, tmp, i;
0045     int ret;
0046 
0047     if (!op || op > 3) {
0048         printk(KERN_WARNING "hw_bitblt_1: Invalid operation: %d\n", op);
0049         return -EINVAL;
0050     }
0051 
0052     if (op != VIA_BITBLT_FILL && !src_mem && src_addr == dst_addr) {
0053         if (src_x < dst_x) {
0054             ge_cmd |= 0x00008000;
0055             src_x += width - 1;
0056             dst_x += width - 1;
0057         }
0058         if (src_y < dst_y) {
0059             ge_cmd |= 0x00004000;
0060             src_y += height - 1;
0061             dst_y += height - 1;
0062         }
0063     }
0064 
0065     if (op == VIA_BITBLT_FILL) {
0066         switch (fill_rop) {
0067         case 0x00: /* blackness */
0068         case 0x5A: /* pattern inversion */
0069         case 0xF0: /* pattern copy */
0070         case 0xFF: /* whiteness */
0071             break;
0072         default:
0073             printk(KERN_WARNING "hw_bitblt_1: Invalid fill rop: "
0074                 "%u\n", fill_rop);
0075             return -EINVAL;
0076         }
0077     }
0078 
0079     ret = viafb_set_bpp(engine, dst_bpp);
0080     if (ret)
0081         return ret;
0082 
0083     if (op != VIA_BITBLT_FILL) {
0084         if (src_x & (op == VIA_BITBLT_MONO ? 0xFFFF8000 : 0xFFFFF000)
0085             || src_y & 0xFFFFF000) {
0086             printk(KERN_WARNING "hw_bitblt_1: Unsupported source "
0087                 "x/y %d %d\n", src_x, src_y);
0088             return -EINVAL;
0089         }
0090         tmp = src_x | (src_y << 16);
0091         writel(tmp, engine + 0x08);
0092     }
0093 
0094     if (dst_x & 0xFFFFF000 || dst_y & 0xFFFFF000) {
0095         printk(KERN_WARNING "hw_bitblt_1: Unsupported destination x/y "
0096             "%d %d\n", dst_x, dst_y);
0097         return -EINVAL;
0098     }
0099     tmp = dst_x | (dst_y << 16);
0100     writel(tmp, engine + 0x0C);
0101 
0102     if ((width - 1) & 0xFFFFF000 || (height - 1) & 0xFFFFF000) {
0103         printk(KERN_WARNING "hw_bitblt_1: Unsupported width/height "
0104             "%d %d\n", width, height);
0105         return -EINVAL;
0106     }
0107     tmp = (width - 1) | ((height - 1) << 16);
0108     writel(tmp, engine + 0x10);
0109 
0110     if (op != VIA_BITBLT_COLOR)
0111         writel(fg_color, engine + 0x18);
0112 
0113     if (op == VIA_BITBLT_MONO)
0114         writel(bg_color, engine + 0x1C);
0115 
0116     if (op != VIA_BITBLT_FILL) {
0117         tmp = src_mem ? 0 : src_addr;
0118         if (dst_addr & 0xE0000007) {
0119             printk(KERN_WARNING "hw_bitblt_1: Unsupported source "
0120                 "address %X\n", tmp);
0121             return -EINVAL;
0122         }
0123         tmp >>= 3;
0124         writel(tmp, engine + 0x30);
0125     }
0126 
0127     if (dst_addr & 0xE0000007) {
0128         printk(KERN_WARNING "hw_bitblt_1: Unsupported destination "
0129             "address %X\n", dst_addr);
0130         return -EINVAL;
0131     }
0132     tmp = dst_addr >> 3;
0133     writel(tmp, engine + 0x34);
0134 
0135     if (op == VIA_BITBLT_FILL)
0136         tmp = 0;
0137     else
0138         tmp = src_pitch;
0139     if (tmp & 0xFFFFC007 || dst_pitch & 0xFFFFC007) {
0140         printk(KERN_WARNING "hw_bitblt_1: Unsupported pitch %X %X\n",
0141             tmp, dst_pitch);
0142         return -EINVAL;
0143     }
0144     tmp = VIA_PITCH_ENABLE | (tmp >> 3) | (dst_pitch << (16 - 3));
0145     writel(tmp, engine + 0x38);
0146 
0147     if (op == VIA_BITBLT_FILL)
0148         ge_cmd |= fill_rop << 24 | 0x00002000 | 0x00000001;
0149     else {
0150         ge_cmd |= 0xCC000000; /* ROP=SRCCOPY */
0151         if (src_mem)
0152             ge_cmd |= 0x00000040;
0153         if (op == VIA_BITBLT_MONO)
0154             ge_cmd |= 0x00000002 | 0x00000100 | 0x00020000;
0155         else
0156             ge_cmd |= 0x00000001;
0157     }
0158     writel(ge_cmd, engine);
0159 
0160     if (op == VIA_BITBLT_FILL || !src_mem)
0161         return 0;
0162 
0163     tmp = (width * height * (op == VIA_BITBLT_MONO ? 1 : (dst_bpp >> 3)) +
0164         3) >> 2;
0165 
0166     for (i = 0; i < tmp; i++)
0167         writel(src_mem[i], engine + VIA_MMIO_BLTBASE);
0168 
0169     return 0;
0170 }
0171 
0172 static int hw_bitblt_2(void __iomem *engine, u8 op, u32 width, u32 height,
0173     u8 dst_bpp, u32 dst_addr, u32 dst_pitch, u32 dst_x, u32 dst_y,
0174     u32 *src_mem, u32 src_addr, u32 src_pitch, u32 src_x, u32 src_y,
0175     u32 fg_color, u32 bg_color, u8 fill_rop)
0176 {
0177     u32 ge_cmd = 0, tmp, i;
0178     int ret;
0179 
0180     if (!op || op > 3) {
0181         printk(KERN_WARNING "hw_bitblt_2: Invalid operation: %d\n", op);
0182         return -EINVAL;
0183     }
0184 
0185     if (op != VIA_BITBLT_FILL && !src_mem && src_addr == dst_addr) {
0186         if (src_x < dst_x) {
0187             ge_cmd |= 0x00008000;
0188             src_x += width - 1;
0189             dst_x += width - 1;
0190         }
0191         if (src_y < dst_y) {
0192             ge_cmd |= 0x00004000;
0193             src_y += height - 1;
0194             dst_y += height - 1;
0195         }
0196     }
0197 
0198     if (op == VIA_BITBLT_FILL) {
0199         switch (fill_rop) {
0200         case 0x00: /* blackness */
0201         case 0x5A: /* pattern inversion */
0202         case 0xF0: /* pattern copy */
0203         case 0xFF: /* whiteness */
0204             break;
0205         default:
0206             printk(KERN_WARNING "hw_bitblt_2: Invalid fill rop: "
0207                 "%u\n", fill_rop);
0208             return -EINVAL;
0209         }
0210     }
0211 
0212     ret = viafb_set_bpp(engine, dst_bpp);
0213     if (ret)
0214         return ret;
0215 
0216     if (op == VIA_BITBLT_FILL)
0217         tmp = 0;
0218     else
0219         tmp = src_pitch;
0220     if (tmp & 0xFFFFC007 || dst_pitch & 0xFFFFC007) {
0221         printk(KERN_WARNING "hw_bitblt_2: Unsupported pitch %X %X\n",
0222             tmp, dst_pitch);
0223         return -EINVAL;
0224     }
0225     tmp = (tmp >> 3) | (dst_pitch << (16 - 3));
0226     writel(tmp, engine + 0x08);
0227 
0228     if ((width - 1) & 0xFFFFF000 || (height - 1) & 0xFFFFF000) {
0229         printk(KERN_WARNING "hw_bitblt_2: Unsupported width/height "
0230             "%d %d\n", width, height);
0231         return -EINVAL;
0232     }
0233     tmp = (width - 1) | ((height - 1) << 16);
0234     writel(tmp, engine + 0x0C);
0235 
0236     if (dst_x & 0xFFFFF000 || dst_y & 0xFFFFF000) {
0237         printk(KERN_WARNING "hw_bitblt_2: Unsupported destination x/y "
0238             "%d %d\n", dst_x, dst_y);
0239         return -EINVAL;
0240     }
0241     tmp = dst_x | (dst_y << 16);
0242     writel(tmp, engine + 0x10);
0243 
0244     if (dst_addr & 0xE0000007) {
0245         printk(KERN_WARNING "hw_bitblt_2: Unsupported destination "
0246             "address %X\n", dst_addr);
0247         return -EINVAL;
0248     }
0249     tmp = dst_addr >> 3;
0250     writel(tmp, engine + 0x14);
0251 
0252     if (op != VIA_BITBLT_FILL) {
0253         if (src_x & (op == VIA_BITBLT_MONO ? 0xFFFF8000 : 0xFFFFF000)
0254             || src_y & 0xFFFFF000) {
0255             printk(KERN_WARNING "hw_bitblt_2: Unsupported source "
0256                 "x/y %d %d\n", src_x, src_y);
0257             return -EINVAL;
0258         }
0259         tmp = src_x | (src_y << 16);
0260         writel(tmp, engine + 0x18);
0261 
0262         tmp = src_mem ? 0 : src_addr;
0263         if (dst_addr & 0xE0000007) {
0264             printk(KERN_WARNING "hw_bitblt_2: Unsupported source "
0265                 "address %X\n", tmp);
0266             return -EINVAL;
0267         }
0268         tmp >>= 3;
0269         writel(tmp, engine + 0x1C);
0270     }
0271 
0272     if (op == VIA_BITBLT_FILL) {
0273         writel(fg_color, engine + 0x58);
0274     } else if (op == VIA_BITBLT_MONO) {
0275         writel(fg_color, engine + 0x4C);
0276         writel(bg_color, engine + 0x50);
0277     }
0278 
0279     if (op == VIA_BITBLT_FILL)
0280         ge_cmd |= fill_rop << 24 | 0x00002000 | 0x00000001;
0281     else {
0282         ge_cmd |= 0xCC000000; /* ROP=SRCCOPY */
0283         if (src_mem)
0284             ge_cmd |= 0x00000040;
0285         if (op == VIA_BITBLT_MONO)
0286             ge_cmd |= 0x00000002 | 0x00000100 | 0x00020000;
0287         else
0288             ge_cmd |= 0x00000001;
0289     }
0290     writel(ge_cmd, engine);
0291 
0292     if (op == VIA_BITBLT_FILL || !src_mem)
0293         return 0;
0294 
0295     tmp = (width * height * (op == VIA_BITBLT_MONO ? 1 : (dst_bpp >> 3)) +
0296         3) >> 2;
0297 
0298     for (i = 0; i < tmp; i++)
0299         writel(src_mem[i], engine + VIA_MMIO_BLTBASE);
0300 
0301     return 0;
0302 }
0303 
0304 int viafb_setup_engine(struct fb_info *info)
0305 {
0306     struct viafb_par *viapar = info->par;
0307     void __iomem *engine;
0308     u32 chip_name = viapar->shared->chip_info.gfx_chip_name;
0309 
0310     engine = viapar->shared->vdev->engine_mmio;
0311     if (!engine) {
0312         printk(KERN_WARNING "viafb_init_accel: ioremap failed, "
0313             "hardware acceleration disabled\n");
0314         return -ENOMEM;
0315     }
0316 
0317     switch (chip_name) {
0318     case UNICHROME_CLE266:
0319     case UNICHROME_K400:
0320     case UNICHROME_K800:
0321     case UNICHROME_PM800:
0322     case UNICHROME_CN700:
0323     case UNICHROME_CX700:
0324     case UNICHROME_CN750:
0325     case UNICHROME_K8M890:
0326     case UNICHROME_P4M890:
0327     case UNICHROME_P4M900:
0328         viapar->shared->hw_bitblt = hw_bitblt_1;
0329         break;
0330     case UNICHROME_VX800:
0331     case UNICHROME_VX855:
0332     case UNICHROME_VX900:
0333         viapar->shared->hw_bitblt = hw_bitblt_2;
0334         break;
0335     default:
0336         viapar->shared->hw_bitblt = NULL;
0337     }
0338 
0339     viapar->fbmem_free -= CURSOR_SIZE;
0340     viapar->shared->cursor_vram_addr = viapar->fbmem_free;
0341     viapar->fbmem_used += CURSOR_SIZE;
0342 
0343     viapar->fbmem_free -= VQ_SIZE;
0344     viapar->shared->vq_vram_addr = viapar->fbmem_free;
0345     viapar->fbmem_used += VQ_SIZE;
0346 
0347 #if IS_ENABLED(CONFIG_VIDEO_VIA_CAMERA)
0348     /*
0349      * Set aside a chunk of framebuffer memory for the camera
0350      * driver.  Someday this driver probably needs a proper allocator
0351      * for fbmem; for now, we just have to do this before the
0352      * framebuffer initializes itself.
0353      *
0354      * As for the size: the engine can handle three frames,
0355      * 16 bits deep, up to VGA resolution.
0356      */
0357     viapar->shared->vdev->camera_fbmem_size = 3*VGA_HEIGHT*VGA_WIDTH*2;
0358     viapar->fbmem_free -= viapar->shared->vdev->camera_fbmem_size;
0359     viapar->fbmem_used += viapar->shared->vdev->camera_fbmem_size;
0360     viapar->shared->vdev->camera_fbmem_offset = viapar->fbmem_free;
0361 #endif
0362 
0363     viafb_reset_engine(viapar);
0364     return 0;
0365 }
0366 
0367 void viafb_reset_engine(struct viafb_par *viapar)
0368 {
0369     void __iomem *engine = viapar->shared->vdev->engine_mmio;
0370     int highest_reg, i;
0371     u32 vq_start_addr, vq_end_addr, vq_start_low, vq_end_low, vq_high,
0372         vq_len, chip_name = viapar->shared->chip_info.gfx_chip_name;
0373 
0374     /* Initialize registers to reset the 2D engine */
0375     switch (viapar->shared->chip_info.twod_engine) {
0376     case VIA_2D_ENG_M1:
0377         highest_reg = 0x5c;
0378         break;
0379     default:
0380         highest_reg = 0x40;
0381         break;
0382     }
0383     for (i = 0; i <= highest_reg; i += 4)
0384         writel(0x0, engine + i);
0385 
0386     /* Init AGP and VQ regs */
0387     switch (chip_name) {
0388     case UNICHROME_K8M890:
0389     case UNICHROME_P4M900:
0390     case UNICHROME_VX800:
0391     case UNICHROME_VX855:
0392     case UNICHROME_VX900:
0393         writel(0x00100000, engine + VIA_REG_CR_TRANSET);
0394         writel(0x680A0000, engine + VIA_REG_CR_TRANSPACE);
0395         writel(0x02000000, engine + VIA_REG_CR_TRANSPACE);
0396         break;
0397 
0398     default:
0399         writel(0x00100000, engine + VIA_REG_TRANSET);
0400         writel(0x00000000, engine + VIA_REG_TRANSPACE);
0401         writel(0x00333004, engine + VIA_REG_TRANSPACE);
0402         writel(0x60000000, engine + VIA_REG_TRANSPACE);
0403         writel(0x61000000, engine + VIA_REG_TRANSPACE);
0404         writel(0x62000000, engine + VIA_REG_TRANSPACE);
0405         writel(0x63000000, engine + VIA_REG_TRANSPACE);
0406         writel(0x64000000, engine + VIA_REG_TRANSPACE);
0407         writel(0x7D000000, engine + VIA_REG_TRANSPACE);
0408 
0409         writel(0xFE020000, engine + VIA_REG_TRANSET);
0410         writel(0x00000000, engine + VIA_REG_TRANSPACE);
0411         break;
0412     }
0413 
0414     /* Enable VQ */
0415     vq_start_addr = viapar->shared->vq_vram_addr;
0416     vq_end_addr = viapar->shared->vq_vram_addr + VQ_SIZE - 1;
0417 
0418     vq_start_low = 0x50000000 | (vq_start_addr & 0xFFFFFF);
0419     vq_end_low = 0x51000000 | (vq_end_addr & 0xFFFFFF);
0420     vq_high = 0x52000000 | ((vq_start_addr & 0xFF000000) >> 24) |
0421         ((vq_end_addr & 0xFF000000) >> 16);
0422     vq_len = 0x53000000 | (VQ_SIZE >> 3);
0423 
0424     switch (chip_name) {
0425     case UNICHROME_K8M890:
0426     case UNICHROME_P4M900:
0427     case UNICHROME_VX800:
0428     case UNICHROME_VX855:
0429     case UNICHROME_VX900:
0430         vq_start_low |= 0x20000000;
0431         vq_end_low |= 0x20000000;
0432         vq_high |= 0x20000000;
0433         vq_len |= 0x20000000;
0434 
0435         writel(0x00100000, engine + VIA_REG_CR_TRANSET);
0436         writel(vq_high, engine + VIA_REG_CR_TRANSPACE);
0437         writel(vq_start_low, engine + VIA_REG_CR_TRANSPACE);
0438         writel(vq_end_low, engine + VIA_REG_CR_TRANSPACE);
0439         writel(vq_len, engine + VIA_REG_CR_TRANSPACE);
0440         writel(0x74301001, engine + VIA_REG_CR_TRANSPACE);
0441         writel(0x00000000, engine + VIA_REG_CR_TRANSPACE);
0442         break;
0443     default:
0444         writel(0x00FE0000, engine + VIA_REG_TRANSET);
0445         writel(0x080003FE, engine + VIA_REG_TRANSPACE);
0446         writel(0x0A00027C, engine + VIA_REG_TRANSPACE);
0447         writel(0x0B000260, engine + VIA_REG_TRANSPACE);
0448         writel(0x0C000274, engine + VIA_REG_TRANSPACE);
0449         writel(0x0D000264, engine + VIA_REG_TRANSPACE);
0450         writel(0x0E000000, engine + VIA_REG_TRANSPACE);
0451         writel(0x0F000020, engine + VIA_REG_TRANSPACE);
0452         writel(0x1000027E, engine + VIA_REG_TRANSPACE);
0453         writel(0x110002FE, engine + VIA_REG_TRANSPACE);
0454         writel(0x200F0060, engine + VIA_REG_TRANSPACE);
0455 
0456         writel(0x00000006, engine + VIA_REG_TRANSPACE);
0457         writel(0x40008C0F, engine + VIA_REG_TRANSPACE);
0458         writel(0x44000000, engine + VIA_REG_TRANSPACE);
0459         writel(0x45080C04, engine + VIA_REG_TRANSPACE);
0460         writel(0x46800408, engine + VIA_REG_TRANSPACE);
0461 
0462         writel(vq_high, engine + VIA_REG_TRANSPACE);
0463         writel(vq_start_low, engine + VIA_REG_TRANSPACE);
0464         writel(vq_end_low, engine + VIA_REG_TRANSPACE);
0465         writel(vq_len, engine + VIA_REG_TRANSPACE);
0466         break;
0467     }
0468 
0469     /* Set Cursor Image Base Address */
0470     writel(viapar->shared->cursor_vram_addr, engine + VIA_REG_CURSOR_MODE);
0471     writel(0x0, engine + VIA_REG_CURSOR_POS);
0472     writel(0x0, engine + VIA_REG_CURSOR_ORG);
0473     writel(0x0, engine + VIA_REG_CURSOR_BG);
0474     writel(0x0, engine + VIA_REG_CURSOR_FG);
0475     return;
0476 }
0477 
0478 void viafb_show_hw_cursor(struct fb_info *info, int Status)
0479 {
0480     struct viafb_par *viapar = info->par;
0481     u32 temp, iga_path = viapar->iga_path;
0482 
0483     temp = readl(viapar->shared->vdev->engine_mmio + VIA_REG_CURSOR_MODE);
0484     switch (Status) {
0485     case HW_Cursor_ON:
0486         temp |= 0x1;
0487         break;
0488     case HW_Cursor_OFF:
0489         temp &= 0xFFFFFFFE;
0490         break;
0491     }
0492     switch (iga_path) {
0493     case IGA2:
0494         temp |= 0x80000000;
0495         break;
0496     case IGA1:
0497     default:
0498         temp &= 0x7FFFFFFF;
0499     }
0500     writel(temp, viapar->shared->vdev->engine_mmio + VIA_REG_CURSOR_MODE);
0501 }
0502 
0503 void viafb_wait_engine_idle(struct fb_info *info)
0504 {
0505     struct viafb_par *viapar = info->par;
0506     int loop = 0;
0507     u32 mask;
0508     void __iomem *engine = viapar->shared->vdev->engine_mmio;
0509 
0510     switch (viapar->shared->chip_info.twod_engine) {
0511     case VIA_2D_ENG_H5:
0512     case VIA_2D_ENG_M1:
0513         mask = VIA_CMD_RGTR_BUSY_M1 | VIA_2D_ENG_BUSY_M1 |
0514                   VIA_3D_ENG_BUSY_M1;
0515         break;
0516     default:
0517         while (!(readl(engine + VIA_REG_STATUS) &
0518                 VIA_VR_QUEUE_BUSY) && (loop < MAXLOOP)) {
0519             loop++;
0520             cpu_relax();
0521         }
0522         mask = VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | VIA_3D_ENG_BUSY;
0523         break;
0524     }
0525 
0526     while ((readl(engine + VIA_REG_STATUS) & mask) && (loop < MAXLOOP)) {
0527         loop++;
0528         cpu_relax();
0529     }
0530 
0531     if (loop >= MAXLOOP)
0532         printk(KERN_ERR "viafb_wait_engine_idle: not syncing\n");
0533 }