18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
48c2ecf20Sopenharmony_ci * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci#include <linux/via-core.h>
88c2ecf20Sopenharmony_ci#include "global.h"
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci/*
118c2ecf20Sopenharmony_ci * Figure out an appropriate bytes-per-pixel setting.
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_cistatic int viafb_set_bpp(void __iomem *engine, u8 bpp)
148c2ecf20Sopenharmony_ci{
158c2ecf20Sopenharmony_ci	u32 gemode;
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci	/* Preserve the reserved bits */
188c2ecf20Sopenharmony_ci	/* Lowest 2 bits to zero gives us no rotation */
198c2ecf20Sopenharmony_ci	gemode = readl(engine + VIA_REG_GEMODE) & 0xfffffcfc;
208c2ecf20Sopenharmony_ci	switch (bpp) {
218c2ecf20Sopenharmony_ci	case 8:
228c2ecf20Sopenharmony_ci		gemode |= VIA_GEM_8bpp;
238c2ecf20Sopenharmony_ci		break;
248c2ecf20Sopenharmony_ci	case 16:
258c2ecf20Sopenharmony_ci		gemode |= VIA_GEM_16bpp;
268c2ecf20Sopenharmony_ci		break;
278c2ecf20Sopenharmony_ci	case 32:
288c2ecf20Sopenharmony_ci		gemode |= VIA_GEM_32bpp;
298c2ecf20Sopenharmony_ci		break;
308c2ecf20Sopenharmony_ci	default:
318c2ecf20Sopenharmony_ci		printk(KERN_WARNING "viafb_set_bpp: Unsupported bpp %d\n", bpp);
328c2ecf20Sopenharmony_ci		return -EINVAL;
338c2ecf20Sopenharmony_ci	}
348c2ecf20Sopenharmony_ci	writel(gemode, engine + VIA_REG_GEMODE);
358c2ecf20Sopenharmony_ci	return 0;
368c2ecf20Sopenharmony_ci}
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic int hw_bitblt_1(void __iomem *engine, u8 op, u32 width, u32 height,
408c2ecf20Sopenharmony_ci	u8 dst_bpp, u32 dst_addr, u32 dst_pitch, u32 dst_x, u32 dst_y,
418c2ecf20Sopenharmony_ci	u32 *src_mem, u32 src_addr, u32 src_pitch, u32 src_x, u32 src_y,
428c2ecf20Sopenharmony_ci	u32 fg_color, u32 bg_color, u8 fill_rop)
438c2ecf20Sopenharmony_ci{
448c2ecf20Sopenharmony_ci	u32 ge_cmd = 0, tmp, i;
458c2ecf20Sopenharmony_ci	int ret;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	if (!op || op > 3) {
488c2ecf20Sopenharmony_ci		printk(KERN_WARNING "hw_bitblt_1: Invalid operation: %d\n", op);
498c2ecf20Sopenharmony_ci		return -EINVAL;
508c2ecf20Sopenharmony_ci	}
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	if (op != VIA_BITBLT_FILL && !src_mem && src_addr == dst_addr) {
538c2ecf20Sopenharmony_ci		if (src_x < dst_x) {
548c2ecf20Sopenharmony_ci			ge_cmd |= 0x00008000;
558c2ecf20Sopenharmony_ci			src_x += width - 1;
568c2ecf20Sopenharmony_ci			dst_x += width - 1;
578c2ecf20Sopenharmony_ci		}
588c2ecf20Sopenharmony_ci		if (src_y < dst_y) {
598c2ecf20Sopenharmony_ci			ge_cmd |= 0x00004000;
608c2ecf20Sopenharmony_ci			src_y += height - 1;
618c2ecf20Sopenharmony_ci			dst_y += height - 1;
628c2ecf20Sopenharmony_ci		}
638c2ecf20Sopenharmony_ci	}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	if (op == VIA_BITBLT_FILL) {
668c2ecf20Sopenharmony_ci		switch (fill_rop) {
678c2ecf20Sopenharmony_ci		case 0x00: /* blackness */
688c2ecf20Sopenharmony_ci		case 0x5A: /* pattern inversion */
698c2ecf20Sopenharmony_ci		case 0xF0: /* pattern copy */
708c2ecf20Sopenharmony_ci		case 0xFF: /* whiteness */
718c2ecf20Sopenharmony_ci			break;
728c2ecf20Sopenharmony_ci		default:
738c2ecf20Sopenharmony_ci			printk(KERN_WARNING "hw_bitblt_1: Invalid fill rop: "
748c2ecf20Sopenharmony_ci				"%u\n", fill_rop);
758c2ecf20Sopenharmony_ci			return -EINVAL;
768c2ecf20Sopenharmony_ci		}
778c2ecf20Sopenharmony_ci	}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	ret = viafb_set_bpp(engine, dst_bpp);
808c2ecf20Sopenharmony_ci	if (ret)
818c2ecf20Sopenharmony_ci		return ret;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	if (op != VIA_BITBLT_FILL) {
848c2ecf20Sopenharmony_ci		if (src_x & (op == VIA_BITBLT_MONO ? 0xFFFF8000 : 0xFFFFF000)
858c2ecf20Sopenharmony_ci			|| src_y & 0xFFFFF000) {
868c2ecf20Sopenharmony_ci			printk(KERN_WARNING "hw_bitblt_1: Unsupported source "
878c2ecf20Sopenharmony_ci				"x/y %d %d\n", src_x, src_y);
888c2ecf20Sopenharmony_ci			return -EINVAL;
898c2ecf20Sopenharmony_ci		}
908c2ecf20Sopenharmony_ci		tmp = src_x | (src_y << 16);
918c2ecf20Sopenharmony_ci		writel(tmp, engine + 0x08);
928c2ecf20Sopenharmony_ci	}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	if (dst_x & 0xFFFFF000 || dst_y & 0xFFFFF000) {
958c2ecf20Sopenharmony_ci		printk(KERN_WARNING "hw_bitblt_1: Unsupported destination x/y "
968c2ecf20Sopenharmony_ci			"%d %d\n", dst_x, dst_y);
978c2ecf20Sopenharmony_ci		return -EINVAL;
988c2ecf20Sopenharmony_ci	}
998c2ecf20Sopenharmony_ci	tmp = dst_x | (dst_y << 16);
1008c2ecf20Sopenharmony_ci	writel(tmp, engine + 0x0C);
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	if ((width - 1) & 0xFFFFF000 || (height - 1) & 0xFFFFF000) {
1038c2ecf20Sopenharmony_ci		printk(KERN_WARNING "hw_bitblt_1: Unsupported width/height "
1048c2ecf20Sopenharmony_ci			"%d %d\n", width, height);
1058c2ecf20Sopenharmony_ci		return -EINVAL;
1068c2ecf20Sopenharmony_ci	}
1078c2ecf20Sopenharmony_ci	tmp = (width - 1) | ((height - 1) << 16);
1088c2ecf20Sopenharmony_ci	writel(tmp, engine + 0x10);
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	if (op != VIA_BITBLT_COLOR)
1118c2ecf20Sopenharmony_ci		writel(fg_color, engine + 0x18);
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	if (op == VIA_BITBLT_MONO)
1148c2ecf20Sopenharmony_ci		writel(bg_color, engine + 0x1C);
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	if (op != VIA_BITBLT_FILL) {
1178c2ecf20Sopenharmony_ci		tmp = src_mem ? 0 : src_addr;
1188c2ecf20Sopenharmony_ci		if (dst_addr & 0xE0000007) {
1198c2ecf20Sopenharmony_ci			printk(KERN_WARNING "hw_bitblt_1: Unsupported source "
1208c2ecf20Sopenharmony_ci				"address %X\n", tmp);
1218c2ecf20Sopenharmony_ci			return -EINVAL;
1228c2ecf20Sopenharmony_ci		}
1238c2ecf20Sopenharmony_ci		tmp >>= 3;
1248c2ecf20Sopenharmony_ci		writel(tmp, engine + 0x30);
1258c2ecf20Sopenharmony_ci	}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	if (dst_addr & 0xE0000007) {
1288c2ecf20Sopenharmony_ci		printk(KERN_WARNING "hw_bitblt_1: Unsupported destination "
1298c2ecf20Sopenharmony_ci			"address %X\n", dst_addr);
1308c2ecf20Sopenharmony_ci		return -EINVAL;
1318c2ecf20Sopenharmony_ci	}
1328c2ecf20Sopenharmony_ci	tmp = dst_addr >> 3;
1338c2ecf20Sopenharmony_ci	writel(tmp, engine + 0x34);
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	if (op == VIA_BITBLT_FILL)
1368c2ecf20Sopenharmony_ci		tmp = 0;
1378c2ecf20Sopenharmony_ci	else
1388c2ecf20Sopenharmony_ci		tmp = src_pitch;
1398c2ecf20Sopenharmony_ci	if (tmp & 0xFFFFC007 || dst_pitch & 0xFFFFC007) {
1408c2ecf20Sopenharmony_ci		printk(KERN_WARNING "hw_bitblt_1: Unsupported pitch %X %X\n",
1418c2ecf20Sopenharmony_ci			tmp, dst_pitch);
1428c2ecf20Sopenharmony_ci		return -EINVAL;
1438c2ecf20Sopenharmony_ci	}
1448c2ecf20Sopenharmony_ci	tmp = VIA_PITCH_ENABLE | (tmp >> 3) | (dst_pitch << (16 - 3));
1458c2ecf20Sopenharmony_ci	writel(tmp, engine + 0x38);
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	if (op == VIA_BITBLT_FILL)
1488c2ecf20Sopenharmony_ci		ge_cmd |= fill_rop << 24 | 0x00002000 | 0x00000001;
1498c2ecf20Sopenharmony_ci	else {
1508c2ecf20Sopenharmony_ci		ge_cmd |= 0xCC000000; /* ROP=SRCCOPY */
1518c2ecf20Sopenharmony_ci		if (src_mem)
1528c2ecf20Sopenharmony_ci			ge_cmd |= 0x00000040;
1538c2ecf20Sopenharmony_ci		if (op == VIA_BITBLT_MONO)
1548c2ecf20Sopenharmony_ci			ge_cmd |= 0x00000002 | 0x00000100 | 0x00020000;
1558c2ecf20Sopenharmony_ci		else
1568c2ecf20Sopenharmony_ci			ge_cmd |= 0x00000001;
1578c2ecf20Sopenharmony_ci	}
1588c2ecf20Sopenharmony_ci	writel(ge_cmd, engine);
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	if (op == VIA_BITBLT_FILL || !src_mem)
1618c2ecf20Sopenharmony_ci		return 0;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	tmp = (width * height * (op == VIA_BITBLT_MONO ? 1 : (dst_bpp >> 3)) +
1648c2ecf20Sopenharmony_ci		3) >> 2;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	for (i = 0; i < tmp; i++)
1678c2ecf20Sopenharmony_ci		writel(src_mem[i], engine + VIA_MMIO_BLTBASE);
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	return 0;
1708c2ecf20Sopenharmony_ci}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_cistatic int hw_bitblt_2(void __iomem *engine, u8 op, u32 width, u32 height,
1738c2ecf20Sopenharmony_ci	u8 dst_bpp, u32 dst_addr, u32 dst_pitch, u32 dst_x, u32 dst_y,
1748c2ecf20Sopenharmony_ci	u32 *src_mem, u32 src_addr, u32 src_pitch, u32 src_x, u32 src_y,
1758c2ecf20Sopenharmony_ci	u32 fg_color, u32 bg_color, u8 fill_rop)
1768c2ecf20Sopenharmony_ci{
1778c2ecf20Sopenharmony_ci	u32 ge_cmd = 0, tmp, i;
1788c2ecf20Sopenharmony_ci	int ret;
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	if (!op || op > 3) {
1818c2ecf20Sopenharmony_ci		printk(KERN_WARNING "hw_bitblt_2: Invalid operation: %d\n", op);
1828c2ecf20Sopenharmony_ci		return -EINVAL;
1838c2ecf20Sopenharmony_ci	}
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	if (op != VIA_BITBLT_FILL && !src_mem && src_addr == dst_addr) {
1868c2ecf20Sopenharmony_ci		if (src_x < dst_x) {
1878c2ecf20Sopenharmony_ci			ge_cmd |= 0x00008000;
1888c2ecf20Sopenharmony_ci			src_x += width - 1;
1898c2ecf20Sopenharmony_ci			dst_x += width - 1;
1908c2ecf20Sopenharmony_ci		}
1918c2ecf20Sopenharmony_ci		if (src_y < dst_y) {
1928c2ecf20Sopenharmony_ci			ge_cmd |= 0x00004000;
1938c2ecf20Sopenharmony_ci			src_y += height - 1;
1948c2ecf20Sopenharmony_ci			dst_y += height - 1;
1958c2ecf20Sopenharmony_ci		}
1968c2ecf20Sopenharmony_ci	}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	if (op == VIA_BITBLT_FILL) {
1998c2ecf20Sopenharmony_ci		switch (fill_rop) {
2008c2ecf20Sopenharmony_ci		case 0x00: /* blackness */
2018c2ecf20Sopenharmony_ci		case 0x5A: /* pattern inversion */
2028c2ecf20Sopenharmony_ci		case 0xF0: /* pattern copy */
2038c2ecf20Sopenharmony_ci		case 0xFF: /* whiteness */
2048c2ecf20Sopenharmony_ci			break;
2058c2ecf20Sopenharmony_ci		default:
2068c2ecf20Sopenharmony_ci			printk(KERN_WARNING "hw_bitblt_2: Invalid fill rop: "
2078c2ecf20Sopenharmony_ci				"%u\n", fill_rop);
2088c2ecf20Sopenharmony_ci			return -EINVAL;
2098c2ecf20Sopenharmony_ci		}
2108c2ecf20Sopenharmony_ci	}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	ret = viafb_set_bpp(engine, dst_bpp);
2138c2ecf20Sopenharmony_ci	if (ret)
2148c2ecf20Sopenharmony_ci		return ret;
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	if (op == VIA_BITBLT_FILL)
2178c2ecf20Sopenharmony_ci		tmp = 0;
2188c2ecf20Sopenharmony_ci	else
2198c2ecf20Sopenharmony_ci		tmp = src_pitch;
2208c2ecf20Sopenharmony_ci	if (tmp & 0xFFFFC007 || dst_pitch & 0xFFFFC007) {
2218c2ecf20Sopenharmony_ci		printk(KERN_WARNING "hw_bitblt_2: Unsupported pitch %X %X\n",
2228c2ecf20Sopenharmony_ci			tmp, dst_pitch);
2238c2ecf20Sopenharmony_ci		return -EINVAL;
2248c2ecf20Sopenharmony_ci	}
2258c2ecf20Sopenharmony_ci	tmp = (tmp >> 3) | (dst_pitch << (16 - 3));
2268c2ecf20Sopenharmony_ci	writel(tmp, engine + 0x08);
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	if ((width - 1) & 0xFFFFF000 || (height - 1) & 0xFFFFF000) {
2298c2ecf20Sopenharmony_ci		printk(KERN_WARNING "hw_bitblt_2: Unsupported width/height "
2308c2ecf20Sopenharmony_ci			"%d %d\n", width, height);
2318c2ecf20Sopenharmony_ci		return -EINVAL;
2328c2ecf20Sopenharmony_ci	}
2338c2ecf20Sopenharmony_ci	tmp = (width - 1) | ((height - 1) << 16);
2348c2ecf20Sopenharmony_ci	writel(tmp, engine + 0x0C);
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	if (dst_x & 0xFFFFF000 || dst_y & 0xFFFFF000) {
2378c2ecf20Sopenharmony_ci		printk(KERN_WARNING "hw_bitblt_2: Unsupported destination x/y "
2388c2ecf20Sopenharmony_ci			"%d %d\n", dst_x, dst_y);
2398c2ecf20Sopenharmony_ci		return -EINVAL;
2408c2ecf20Sopenharmony_ci	}
2418c2ecf20Sopenharmony_ci	tmp = dst_x | (dst_y << 16);
2428c2ecf20Sopenharmony_ci	writel(tmp, engine + 0x10);
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	if (dst_addr & 0xE0000007) {
2458c2ecf20Sopenharmony_ci		printk(KERN_WARNING "hw_bitblt_2: Unsupported destination "
2468c2ecf20Sopenharmony_ci			"address %X\n", dst_addr);
2478c2ecf20Sopenharmony_ci		return -EINVAL;
2488c2ecf20Sopenharmony_ci	}
2498c2ecf20Sopenharmony_ci	tmp = dst_addr >> 3;
2508c2ecf20Sopenharmony_ci	writel(tmp, engine + 0x14);
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	if (op != VIA_BITBLT_FILL) {
2538c2ecf20Sopenharmony_ci		if (src_x & (op == VIA_BITBLT_MONO ? 0xFFFF8000 : 0xFFFFF000)
2548c2ecf20Sopenharmony_ci			|| src_y & 0xFFFFF000) {
2558c2ecf20Sopenharmony_ci			printk(KERN_WARNING "hw_bitblt_2: Unsupported source "
2568c2ecf20Sopenharmony_ci				"x/y %d %d\n", src_x, src_y);
2578c2ecf20Sopenharmony_ci			return -EINVAL;
2588c2ecf20Sopenharmony_ci		}
2598c2ecf20Sopenharmony_ci		tmp = src_x | (src_y << 16);
2608c2ecf20Sopenharmony_ci		writel(tmp, engine + 0x18);
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci		tmp = src_mem ? 0 : src_addr;
2638c2ecf20Sopenharmony_ci		if (dst_addr & 0xE0000007) {
2648c2ecf20Sopenharmony_ci			printk(KERN_WARNING "hw_bitblt_2: Unsupported source "
2658c2ecf20Sopenharmony_ci				"address %X\n", tmp);
2668c2ecf20Sopenharmony_ci			return -EINVAL;
2678c2ecf20Sopenharmony_ci		}
2688c2ecf20Sopenharmony_ci		tmp >>= 3;
2698c2ecf20Sopenharmony_ci		writel(tmp, engine + 0x1C);
2708c2ecf20Sopenharmony_ci	}
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	if (op == VIA_BITBLT_FILL) {
2738c2ecf20Sopenharmony_ci		writel(fg_color, engine + 0x58);
2748c2ecf20Sopenharmony_ci	} else if (op == VIA_BITBLT_MONO) {
2758c2ecf20Sopenharmony_ci		writel(fg_color, engine + 0x4C);
2768c2ecf20Sopenharmony_ci		writel(bg_color, engine + 0x50);
2778c2ecf20Sopenharmony_ci	}
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	if (op == VIA_BITBLT_FILL)
2808c2ecf20Sopenharmony_ci		ge_cmd |= fill_rop << 24 | 0x00002000 | 0x00000001;
2818c2ecf20Sopenharmony_ci	else {
2828c2ecf20Sopenharmony_ci		ge_cmd |= 0xCC000000; /* ROP=SRCCOPY */
2838c2ecf20Sopenharmony_ci		if (src_mem)
2848c2ecf20Sopenharmony_ci			ge_cmd |= 0x00000040;
2858c2ecf20Sopenharmony_ci		if (op == VIA_BITBLT_MONO)
2868c2ecf20Sopenharmony_ci			ge_cmd |= 0x00000002 | 0x00000100 | 0x00020000;
2878c2ecf20Sopenharmony_ci		else
2888c2ecf20Sopenharmony_ci			ge_cmd |= 0x00000001;
2898c2ecf20Sopenharmony_ci	}
2908c2ecf20Sopenharmony_ci	writel(ge_cmd, engine);
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	if (op == VIA_BITBLT_FILL || !src_mem)
2938c2ecf20Sopenharmony_ci		return 0;
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	tmp = (width * height * (op == VIA_BITBLT_MONO ? 1 : (dst_bpp >> 3)) +
2968c2ecf20Sopenharmony_ci		3) >> 2;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	for (i = 0; i < tmp; i++)
2998c2ecf20Sopenharmony_ci		writel(src_mem[i], engine + VIA_MMIO_BLTBASE);
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	return 0;
3028c2ecf20Sopenharmony_ci}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ciint viafb_setup_engine(struct fb_info *info)
3058c2ecf20Sopenharmony_ci{
3068c2ecf20Sopenharmony_ci	struct viafb_par *viapar = info->par;
3078c2ecf20Sopenharmony_ci	void __iomem *engine;
3088c2ecf20Sopenharmony_ci	u32 chip_name = viapar->shared->chip_info.gfx_chip_name;
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	engine = viapar->shared->vdev->engine_mmio;
3118c2ecf20Sopenharmony_ci	if (!engine) {
3128c2ecf20Sopenharmony_ci		printk(KERN_WARNING "viafb_init_accel: ioremap failed, "
3138c2ecf20Sopenharmony_ci			"hardware acceleration disabled\n");
3148c2ecf20Sopenharmony_ci		return -ENOMEM;
3158c2ecf20Sopenharmony_ci	}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	switch (chip_name) {
3188c2ecf20Sopenharmony_ci	case UNICHROME_CLE266:
3198c2ecf20Sopenharmony_ci	case UNICHROME_K400:
3208c2ecf20Sopenharmony_ci	case UNICHROME_K800:
3218c2ecf20Sopenharmony_ci	case UNICHROME_PM800:
3228c2ecf20Sopenharmony_ci	case UNICHROME_CN700:
3238c2ecf20Sopenharmony_ci	case UNICHROME_CX700:
3248c2ecf20Sopenharmony_ci	case UNICHROME_CN750:
3258c2ecf20Sopenharmony_ci	case UNICHROME_K8M890:
3268c2ecf20Sopenharmony_ci	case UNICHROME_P4M890:
3278c2ecf20Sopenharmony_ci	case UNICHROME_P4M900:
3288c2ecf20Sopenharmony_ci		viapar->shared->hw_bitblt = hw_bitblt_1;
3298c2ecf20Sopenharmony_ci		break;
3308c2ecf20Sopenharmony_ci	case UNICHROME_VX800:
3318c2ecf20Sopenharmony_ci	case UNICHROME_VX855:
3328c2ecf20Sopenharmony_ci	case UNICHROME_VX900:
3338c2ecf20Sopenharmony_ci		viapar->shared->hw_bitblt = hw_bitblt_2;
3348c2ecf20Sopenharmony_ci		break;
3358c2ecf20Sopenharmony_ci	default:
3368c2ecf20Sopenharmony_ci		viapar->shared->hw_bitblt = NULL;
3378c2ecf20Sopenharmony_ci	}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	viapar->fbmem_free -= CURSOR_SIZE;
3408c2ecf20Sopenharmony_ci	viapar->shared->cursor_vram_addr = viapar->fbmem_free;
3418c2ecf20Sopenharmony_ci	viapar->fbmem_used += CURSOR_SIZE;
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	viapar->fbmem_free -= VQ_SIZE;
3448c2ecf20Sopenharmony_ci	viapar->shared->vq_vram_addr = viapar->fbmem_free;
3458c2ecf20Sopenharmony_ci	viapar->fbmem_used += VQ_SIZE;
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_VIDEO_VIA_CAMERA)
3488c2ecf20Sopenharmony_ci	/*
3498c2ecf20Sopenharmony_ci	 * Set aside a chunk of framebuffer memory for the camera
3508c2ecf20Sopenharmony_ci	 * driver.  Someday this driver probably needs a proper allocator
3518c2ecf20Sopenharmony_ci	 * for fbmem; for now, we just have to do this before the
3528c2ecf20Sopenharmony_ci	 * framebuffer initializes itself.
3538c2ecf20Sopenharmony_ci	 *
3548c2ecf20Sopenharmony_ci	 * As for the size: the engine can handle three frames,
3558c2ecf20Sopenharmony_ci	 * 16 bits deep, up to VGA resolution.
3568c2ecf20Sopenharmony_ci	 */
3578c2ecf20Sopenharmony_ci	viapar->shared->vdev->camera_fbmem_size = 3*VGA_HEIGHT*VGA_WIDTH*2;
3588c2ecf20Sopenharmony_ci	viapar->fbmem_free -= viapar->shared->vdev->camera_fbmem_size;
3598c2ecf20Sopenharmony_ci	viapar->fbmem_used += viapar->shared->vdev->camera_fbmem_size;
3608c2ecf20Sopenharmony_ci	viapar->shared->vdev->camera_fbmem_offset = viapar->fbmem_free;
3618c2ecf20Sopenharmony_ci#endif
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	viafb_reset_engine(viapar);
3648c2ecf20Sopenharmony_ci	return 0;
3658c2ecf20Sopenharmony_ci}
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_civoid viafb_reset_engine(struct viafb_par *viapar)
3688c2ecf20Sopenharmony_ci{
3698c2ecf20Sopenharmony_ci	void __iomem *engine = viapar->shared->vdev->engine_mmio;
3708c2ecf20Sopenharmony_ci	int highest_reg, i;
3718c2ecf20Sopenharmony_ci	u32 vq_start_addr, vq_end_addr, vq_start_low, vq_end_low, vq_high,
3728c2ecf20Sopenharmony_ci		vq_len, chip_name = viapar->shared->chip_info.gfx_chip_name;
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	/* Initialize registers to reset the 2D engine */
3758c2ecf20Sopenharmony_ci	switch (viapar->shared->chip_info.twod_engine) {
3768c2ecf20Sopenharmony_ci	case VIA_2D_ENG_M1:
3778c2ecf20Sopenharmony_ci		highest_reg = 0x5c;
3788c2ecf20Sopenharmony_ci		break;
3798c2ecf20Sopenharmony_ci	default:
3808c2ecf20Sopenharmony_ci		highest_reg = 0x40;
3818c2ecf20Sopenharmony_ci		break;
3828c2ecf20Sopenharmony_ci	}
3838c2ecf20Sopenharmony_ci	for (i = 0; i <= highest_reg; i += 4)
3848c2ecf20Sopenharmony_ci		writel(0x0, engine + i);
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	/* Init AGP and VQ regs */
3878c2ecf20Sopenharmony_ci	switch (chip_name) {
3888c2ecf20Sopenharmony_ci	case UNICHROME_K8M890:
3898c2ecf20Sopenharmony_ci	case UNICHROME_P4M900:
3908c2ecf20Sopenharmony_ci	case UNICHROME_VX800:
3918c2ecf20Sopenharmony_ci	case UNICHROME_VX855:
3928c2ecf20Sopenharmony_ci	case UNICHROME_VX900:
3938c2ecf20Sopenharmony_ci		writel(0x00100000, engine + VIA_REG_CR_TRANSET);
3948c2ecf20Sopenharmony_ci		writel(0x680A0000, engine + VIA_REG_CR_TRANSPACE);
3958c2ecf20Sopenharmony_ci		writel(0x02000000, engine + VIA_REG_CR_TRANSPACE);
3968c2ecf20Sopenharmony_ci		break;
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	default:
3998c2ecf20Sopenharmony_ci		writel(0x00100000, engine + VIA_REG_TRANSET);
4008c2ecf20Sopenharmony_ci		writel(0x00000000, engine + VIA_REG_TRANSPACE);
4018c2ecf20Sopenharmony_ci		writel(0x00333004, engine + VIA_REG_TRANSPACE);
4028c2ecf20Sopenharmony_ci		writel(0x60000000, engine + VIA_REG_TRANSPACE);
4038c2ecf20Sopenharmony_ci		writel(0x61000000, engine + VIA_REG_TRANSPACE);
4048c2ecf20Sopenharmony_ci		writel(0x62000000, engine + VIA_REG_TRANSPACE);
4058c2ecf20Sopenharmony_ci		writel(0x63000000, engine + VIA_REG_TRANSPACE);
4068c2ecf20Sopenharmony_ci		writel(0x64000000, engine + VIA_REG_TRANSPACE);
4078c2ecf20Sopenharmony_ci		writel(0x7D000000, engine + VIA_REG_TRANSPACE);
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci		writel(0xFE020000, engine + VIA_REG_TRANSET);
4108c2ecf20Sopenharmony_ci		writel(0x00000000, engine + VIA_REG_TRANSPACE);
4118c2ecf20Sopenharmony_ci		break;
4128c2ecf20Sopenharmony_ci	}
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	/* Enable VQ */
4158c2ecf20Sopenharmony_ci	vq_start_addr = viapar->shared->vq_vram_addr;
4168c2ecf20Sopenharmony_ci	vq_end_addr = viapar->shared->vq_vram_addr + VQ_SIZE - 1;
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	vq_start_low = 0x50000000 | (vq_start_addr & 0xFFFFFF);
4198c2ecf20Sopenharmony_ci	vq_end_low = 0x51000000 | (vq_end_addr & 0xFFFFFF);
4208c2ecf20Sopenharmony_ci	vq_high = 0x52000000 | ((vq_start_addr & 0xFF000000) >> 24) |
4218c2ecf20Sopenharmony_ci		((vq_end_addr & 0xFF000000) >> 16);
4228c2ecf20Sopenharmony_ci	vq_len = 0x53000000 | (VQ_SIZE >> 3);
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	switch (chip_name) {
4258c2ecf20Sopenharmony_ci	case UNICHROME_K8M890:
4268c2ecf20Sopenharmony_ci	case UNICHROME_P4M900:
4278c2ecf20Sopenharmony_ci	case UNICHROME_VX800:
4288c2ecf20Sopenharmony_ci	case UNICHROME_VX855:
4298c2ecf20Sopenharmony_ci	case UNICHROME_VX900:
4308c2ecf20Sopenharmony_ci		vq_start_low |= 0x20000000;
4318c2ecf20Sopenharmony_ci		vq_end_low |= 0x20000000;
4328c2ecf20Sopenharmony_ci		vq_high |= 0x20000000;
4338c2ecf20Sopenharmony_ci		vq_len |= 0x20000000;
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci		writel(0x00100000, engine + VIA_REG_CR_TRANSET);
4368c2ecf20Sopenharmony_ci		writel(vq_high, engine + VIA_REG_CR_TRANSPACE);
4378c2ecf20Sopenharmony_ci		writel(vq_start_low, engine + VIA_REG_CR_TRANSPACE);
4388c2ecf20Sopenharmony_ci		writel(vq_end_low, engine + VIA_REG_CR_TRANSPACE);
4398c2ecf20Sopenharmony_ci		writel(vq_len, engine + VIA_REG_CR_TRANSPACE);
4408c2ecf20Sopenharmony_ci		writel(0x74301001, engine + VIA_REG_CR_TRANSPACE);
4418c2ecf20Sopenharmony_ci		writel(0x00000000, engine + VIA_REG_CR_TRANSPACE);
4428c2ecf20Sopenharmony_ci		break;
4438c2ecf20Sopenharmony_ci	default:
4448c2ecf20Sopenharmony_ci		writel(0x00FE0000, engine + VIA_REG_TRANSET);
4458c2ecf20Sopenharmony_ci		writel(0x080003FE, engine + VIA_REG_TRANSPACE);
4468c2ecf20Sopenharmony_ci		writel(0x0A00027C, engine + VIA_REG_TRANSPACE);
4478c2ecf20Sopenharmony_ci		writel(0x0B000260, engine + VIA_REG_TRANSPACE);
4488c2ecf20Sopenharmony_ci		writel(0x0C000274, engine + VIA_REG_TRANSPACE);
4498c2ecf20Sopenharmony_ci		writel(0x0D000264, engine + VIA_REG_TRANSPACE);
4508c2ecf20Sopenharmony_ci		writel(0x0E000000, engine + VIA_REG_TRANSPACE);
4518c2ecf20Sopenharmony_ci		writel(0x0F000020, engine + VIA_REG_TRANSPACE);
4528c2ecf20Sopenharmony_ci		writel(0x1000027E, engine + VIA_REG_TRANSPACE);
4538c2ecf20Sopenharmony_ci		writel(0x110002FE, engine + VIA_REG_TRANSPACE);
4548c2ecf20Sopenharmony_ci		writel(0x200F0060, engine + VIA_REG_TRANSPACE);
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci		writel(0x00000006, engine + VIA_REG_TRANSPACE);
4578c2ecf20Sopenharmony_ci		writel(0x40008C0F, engine + VIA_REG_TRANSPACE);
4588c2ecf20Sopenharmony_ci		writel(0x44000000, engine + VIA_REG_TRANSPACE);
4598c2ecf20Sopenharmony_ci		writel(0x45080C04, engine + VIA_REG_TRANSPACE);
4608c2ecf20Sopenharmony_ci		writel(0x46800408, engine + VIA_REG_TRANSPACE);
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci		writel(vq_high, engine + VIA_REG_TRANSPACE);
4638c2ecf20Sopenharmony_ci		writel(vq_start_low, engine + VIA_REG_TRANSPACE);
4648c2ecf20Sopenharmony_ci		writel(vq_end_low, engine + VIA_REG_TRANSPACE);
4658c2ecf20Sopenharmony_ci		writel(vq_len, engine + VIA_REG_TRANSPACE);
4668c2ecf20Sopenharmony_ci		break;
4678c2ecf20Sopenharmony_ci	}
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	/* Set Cursor Image Base Address */
4708c2ecf20Sopenharmony_ci	writel(viapar->shared->cursor_vram_addr, engine + VIA_REG_CURSOR_MODE);
4718c2ecf20Sopenharmony_ci	writel(0x0, engine + VIA_REG_CURSOR_POS);
4728c2ecf20Sopenharmony_ci	writel(0x0, engine + VIA_REG_CURSOR_ORG);
4738c2ecf20Sopenharmony_ci	writel(0x0, engine + VIA_REG_CURSOR_BG);
4748c2ecf20Sopenharmony_ci	writel(0x0, engine + VIA_REG_CURSOR_FG);
4758c2ecf20Sopenharmony_ci	return;
4768c2ecf20Sopenharmony_ci}
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_civoid viafb_show_hw_cursor(struct fb_info *info, int Status)
4798c2ecf20Sopenharmony_ci{
4808c2ecf20Sopenharmony_ci	struct viafb_par *viapar = info->par;
4818c2ecf20Sopenharmony_ci	u32 temp, iga_path = viapar->iga_path;
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	temp = readl(viapar->shared->vdev->engine_mmio + VIA_REG_CURSOR_MODE);
4848c2ecf20Sopenharmony_ci	switch (Status) {
4858c2ecf20Sopenharmony_ci	case HW_Cursor_ON:
4868c2ecf20Sopenharmony_ci		temp |= 0x1;
4878c2ecf20Sopenharmony_ci		break;
4888c2ecf20Sopenharmony_ci	case HW_Cursor_OFF:
4898c2ecf20Sopenharmony_ci		temp &= 0xFFFFFFFE;
4908c2ecf20Sopenharmony_ci		break;
4918c2ecf20Sopenharmony_ci	}
4928c2ecf20Sopenharmony_ci	switch (iga_path) {
4938c2ecf20Sopenharmony_ci	case IGA2:
4948c2ecf20Sopenharmony_ci		temp |= 0x80000000;
4958c2ecf20Sopenharmony_ci		break;
4968c2ecf20Sopenharmony_ci	case IGA1:
4978c2ecf20Sopenharmony_ci	default:
4988c2ecf20Sopenharmony_ci		temp &= 0x7FFFFFFF;
4998c2ecf20Sopenharmony_ci	}
5008c2ecf20Sopenharmony_ci	writel(temp, viapar->shared->vdev->engine_mmio + VIA_REG_CURSOR_MODE);
5018c2ecf20Sopenharmony_ci}
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_civoid viafb_wait_engine_idle(struct fb_info *info)
5048c2ecf20Sopenharmony_ci{
5058c2ecf20Sopenharmony_ci	struct viafb_par *viapar = info->par;
5068c2ecf20Sopenharmony_ci	int loop = 0;
5078c2ecf20Sopenharmony_ci	u32 mask;
5088c2ecf20Sopenharmony_ci	void __iomem *engine = viapar->shared->vdev->engine_mmio;
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	switch (viapar->shared->chip_info.twod_engine) {
5118c2ecf20Sopenharmony_ci	case VIA_2D_ENG_H5:
5128c2ecf20Sopenharmony_ci	case VIA_2D_ENG_M1:
5138c2ecf20Sopenharmony_ci		mask = VIA_CMD_RGTR_BUSY_M1 | VIA_2D_ENG_BUSY_M1 |
5148c2ecf20Sopenharmony_ci			      VIA_3D_ENG_BUSY_M1;
5158c2ecf20Sopenharmony_ci		break;
5168c2ecf20Sopenharmony_ci	default:
5178c2ecf20Sopenharmony_ci		while (!(readl(engine + VIA_REG_STATUS) &
5188c2ecf20Sopenharmony_ci				VIA_VR_QUEUE_BUSY) && (loop < MAXLOOP)) {
5198c2ecf20Sopenharmony_ci			loop++;
5208c2ecf20Sopenharmony_ci			cpu_relax();
5218c2ecf20Sopenharmony_ci		}
5228c2ecf20Sopenharmony_ci		mask = VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | VIA_3D_ENG_BUSY;
5238c2ecf20Sopenharmony_ci		break;
5248c2ecf20Sopenharmony_ci	}
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	while ((readl(engine + VIA_REG_STATUS) & mask) && (loop < MAXLOOP)) {
5278c2ecf20Sopenharmony_ci		loop++;
5288c2ecf20Sopenharmony_ci		cpu_relax();
5298c2ecf20Sopenharmony_ci	}
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	if (loop >= MAXLOOP)
5328c2ecf20Sopenharmony_ci		printk(KERN_ERR "viafb_wait_engine_idle: not syncing\n");
5338c2ecf20Sopenharmony_ci}
534