162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
462306a36Sopenharmony_ci * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci#include <linux/via-core.h>
862306a36Sopenharmony_ci#include "global.h"
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci/*
1162306a36Sopenharmony_ci * Figure out an appropriate bytes-per-pixel setting.
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_cistatic int viafb_set_bpp(void __iomem *engine, u8 bpp)
1462306a36Sopenharmony_ci{
1562306a36Sopenharmony_ci	u32 gemode;
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci	/* Preserve the reserved bits */
1862306a36Sopenharmony_ci	/* Lowest 2 bits to zero gives us no rotation */
1962306a36Sopenharmony_ci	gemode = readl(engine + VIA_REG_GEMODE) & 0xfffffcfc;
2062306a36Sopenharmony_ci	switch (bpp) {
2162306a36Sopenharmony_ci	case 8:
2262306a36Sopenharmony_ci		gemode |= VIA_GEM_8bpp;
2362306a36Sopenharmony_ci		break;
2462306a36Sopenharmony_ci	case 16:
2562306a36Sopenharmony_ci		gemode |= VIA_GEM_16bpp;
2662306a36Sopenharmony_ci		break;
2762306a36Sopenharmony_ci	case 32:
2862306a36Sopenharmony_ci		gemode |= VIA_GEM_32bpp;
2962306a36Sopenharmony_ci		break;
3062306a36Sopenharmony_ci	default:
3162306a36Sopenharmony_ci		printk(KERN_WARNING "viafb_set_bpp: Unsupported bpp %d\n", bpp);
3262306a36Sopenharmony_ci		return -EINVAL;
3362306a36Sopenharmony_ci	}
3462306a36Sopenharmony_ci	writel(gemode, engine + VIA_REG_GEMODE);
3562306a36Sopenharmony_ci	return 0;
3662306a36Sopenharmony_ci}
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistatic int hw_bitblt_1(void __iomem *engine, u8 op, u32 width, u32 height,
4062306a36Sopenharmony_ci	u8 dst_bpp, u32 dst_addr, u32 dst_pitch, u32 dst_x, u32 dst_y,
4162306a36Sopenharmony_ci	u32 *src_mem, u32 src_addr, u32 src_pitch, u32 src_x, u32 src_y,
4262306a36Sopenharmony_ci	u32 fg_color, u32 bg_color, u8 fill_rop)
4362306a36Sopenharmony_ci{
4462306a36Sopenharmony_ci	u32 ge_cmd = 0, tmp, i;
4562306a36Sopenharmony_ci	int ret;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	if (!op || op > 3) {
4862306a36Sopenharmony_ci		printk(KERN_WARNING "hw_bitblt_1: Invalid operation: %d\n", op);
4962306a36Sopenharmony_ci		return -EINVAL;
5062306a36Sopenharmony_ci	}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	if (op != VIA_BITBLT_FILL && !src_mem && src_addr == dst_addr) {
5362306a36Sopenharmony_ci		if (src_x < dst_x) {
5462306a36Sopenharmony_ci			ge_cmd |= 0x00008000;
5562306a36Sopenharmony_ci			src_x += width - 1;
5662306a36Sopenharmony_ci			dst_x += width - 1;
5762306a36Sopenharmony_ci		}
5862306a36Sopenharmony_ci		if (src_y < dst_y) {
5962306a36Sopenharmony_ci			ge_cmd |= 0x00004000;
6062306a36Sopenharmony_ci			src_y += height - 1;
6162306a36Sopenharmony_ci			dst_y += height - 1;
6262306a36Sopenharmony_ci		}
6362306a36Sopenharmony_ci	}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	if (op == VIA_BITBLT_FILL) {
6662306a36Sopenharmony_ci		switch (fill_rop) {
6762306a36Sopenharmony_ci		case 0x00: /* blackness */
6862306a36Sopenharmony_ci		case 0x5A: /* pattern inversion */
6962306a36Sopenharmony_ci		case 0xF0: /* pattern copy */
7062306a36Sopenharmony_ci		case 0xFF: /* whiteness */
7162306a36Sopenharmony_ci			break;
7262306a36Sopenharmony_ci		default:
7362306a36Sopenharmony_ci			printk(KERN_WARNING "hw_bitblt_1: Invalid fill rop: "
7462306a36Sopenharmony_ci				"%u\n", fill_rop);
7562306a36Sopenharmony_ci			return -EINVAL;
7662306a36Sopenharmony_ci		}
7762306a36Sopenharmony_ci	}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	ret = viafb_set_bpp(engine, dst_bpp);
8062306a36Sopenharmony_ci	if (ret)
8162306a36Sopenharmony_ci		return ret;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	if (op != VIA_BITBLT_FILL) {
8462306a36Sopenharmony_ci		if (src_x & (op == VIA_BITBLT_MONO ? 0xFFFF8000 : 0xFFFFF000)
8562306a36Sopenharmony_ci			|| src_y & 0xFFFFF000) {
8662306a36Sopenharmony_ci			printk(KERN_WARNING "hw_bitblt_1: Unsupported source "
8762306a36Sopenharmony_ci				"x/y %d %d\n", src_x, src_y);
8862306a36Sopenharmony_ci			return -EINVAL;
8962306a36Sopenharmony_ci		}
9062306a36Sopenharmony_ci		tmp = src_x | (src_y << 16);
9162306a36Sopenharmony_ci		writel(tmp, engine + 0x08);
9262306a36Sopenharmony_ci	}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	if (dst_x & 0xFFFFF000 || dst_y & 0xFFFFF000) {
9562306a36Sopenharmony_ci		printk(KERN_WARNING "hw_bitblt_1: Unsupported destination x/y "
9662306a36Sopenharmony_ci			"%d %d\n", dst_x, dst_y);
9762306a36Sopenharmony_ci		return -EINVAL;
9862306a36Sopenharmony_ci	}
9962306a36Sopenharmony_ci	tmp = dst_x | (dst_y << 16);
10062306a36Sopenharmony_ci	writel(tmp, engine + 0x0C);
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	if ((width - 1) & 0xFFFFF000 || (height - 1) & 0xFFFFF000) {
10362306a36Sopenharmony_ci		printk(KERN_WARNING "hw_bitblt_1: Unsupported width/height "
10462306a36Sopenharmony_ci			"%d %d\n", width, height);
10562306a36Sopenharmony_ci		return -EINVAL;
10662306a36Sopenharmony_ci	}
10762306a36Sopenharmony_ci	tmp = (width - 1) | ((height - 1) << 16);
10862306a36Sopenharmony_ci	writel(tmp, engine + 0x10);
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	if (op != VIA_BITBLT_COLOR)
11162306a36Sopenharmony_ci		writel(fg_color, engine + 0x18);
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	if (op == VIA_BITBLT_MONO)
11462306a36Sopenharmony_ci		writel(bg_color, engine + 0x1C);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	if (op != VIA_BITBLT_FILL) {
11762306a36Sopenharmony_ci		tmp = src_mem ? 0 : src_addr;
11862306a36Sopenharmony_ci		if (dst_addr & 0xE0000007) {
11962306a36Sopenharmony_ci			printk(KERN_WARNING "hw_bitblt_1: Unsupported source "
12062306a36Sopenharmony_ci				"address %X\n", tmp);
12162306a36Sopenharmony_ci			return -EINVAL;
12262306a36Sopenharmony_ci		}
12362306a36Sopenharmony_ci		tmp >>= 3;
12462306a36Sopenharmony_ci		writel(tmp, engine + 0x30);
12562306a36Sopenharmony_ci	}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	if (dst_addr & 0xE0000007) {
12862306a36Sopenharmony_ci		printk(KERN_WARNING "hw_bitblt_1: Unsupported destination "
12962306a36Sopenharmony_ci			"address %X\n", dst_addr);
13062306a36Sopenharmony_ci		return -EINVAL;
13162306a36Sopenharmony_ci	}
13262306a36Sopenharmony_ci	tmp = dst_addr >> 3;
13362306a36Sopenharmony_ci	writel(tmp, engine + 0x34);
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	if (op == VIA_BITBLT_FILL)
13662306a36Sopenharmony_ci		tmp = 0;
13762306a36Sopenharmony_ci	else
13862306a36Sopenharmony_ci		tmp = src_pitch;
13962306a36Sopenharmony_ci	if (tmp & 0xFFFFC007 || dst_pitch & 0xFFFFC007) {
14062306a36Sopenharmony_ci		printk(KERN_WARNING "hw_bitblt_1: Unsupported pitch %X %X\n",
14162306a36Sopenharmony_ci			tmp, dst_pitch);
14262306a36Sopenharmony_ci		return -EINVAL;
14362306a36Sopenharmony_ci	}
14462306a36Sopenharmony_ci	tmp = VIA_PITCH_ENABLE | (tmp >> 3) | (dst_pitch << (16 - 3));
14562306a36Sopenharmony_ci	writel(tmp, engine + 0x38);
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	if (op == VIA_BITBLT_FILL)
14862306a36Sopenharmony_ci		ge_cmd |= fill_rop << 24 | 0x00002000 | 0x00000001;
14962306a36Sopenharmony_ci	else {
15062306a36Sopenharmony_ci		ge_cmd |= 0xCC000000; /* ROP=SRCCOPY */
15162306a36Sopenharmony_ci		if (src_mem)
15262306a36Sopenharmony_ci			ge_cmd |= 0x00000040;
15362306a36Sopenharmony_ci		if (op == VIA_BITBLT_MONO)
15462306a36Sopenharmony_ci			ge_cmd |= 0x00000002 | 0x00000100 | 0x00020000;
15562306a36Sopenharmony_ci		else
15662306a36Sopenharmony_ci			ge_cmd |= 0x00000001;
15762306a36Sopenharmony_ci	}
15862306a36Sopenharmony_ci	writel(ge_cmd, engine);
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	if (op == VIA_BITBLT_FILL || !src_mem)
16162306a36Sopenharmony_ci		return 0;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	tmp = (width * height * (op == VIA_BITBLT_MONO ? 1 : (dst_bpp >> 3)) +
16462306a36Sopenharmony_ci		3) >> 2;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	for (i = 0; i < tmp; i++)
16762306a36Sopenharmony_ci		writel(src_mem[i], engine + VIA_MMIO_BLTBASE);
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	return 0;
17062306a36Sopenharmony_ci}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_cistatic int hw_bitblt_2(void __iomem *engine, u8 op, u32 width, u32 height,
17362306a36Sopenharmony_ci	u8 dst_bpp, u32 dst_addr, u32 dst_pitch, u32 dst_x, u32 dst_y,
17462306a36Sopenharmony_ci	u32 *src_mem, u32 src_addr, u32 src_pitch, u32 src_x, u32 src_y,
17562306a36Sopenharmony_ci	u32 fg_color, u32 bg_color, u8 fill_rop)
17662306a36Sopenharmony_ci{
17762306a36Sopenharmony_ci	u32 ge_cmd = 0, tmp, i;
17862306a36Sopenharmony_ci	int ret;
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	if (!op || op > 3) {
18162306a36Sopenharmony_ci		printk(KERN_WARNING "hw_bitblt_2: Invalid operation: %d\n", op);
18262306a36Sopenharmony_ci		return -EINVAL;
18362306a36Sopenharmony_ci	}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	if (op != VIA_BITBLT_FILL && !src_mem && src_addr == dst_addr) {
18662306a36Sopenharmony_ci		if (src_x < dst_x) {
18762306a36Sopenharmony_ci			ge_cmd |= 0x00008000;
18862306a36Sopenharmony_ci			src_x += width - 1;
18962306a36Sopenharmony_ci			dst_x += width - 1;
19062306a36Sopenharmony_ci		}
19162306a36Sopenharmony_ci		if (src_y < dst_y) {
19262306a36Sopenharmony_ci			ge_cmd |= 0x00004000;
19362306a36Sopenharmony_ci			src_y += height - 1;
19462306a36Sopenharmony_ci			dst_y += height - 1;
19562306a36Sopenharmony_ci		}
19662306a36Sopenharmony_ci	}
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	if (op == VIA_BITBLT_FILL) {
19962306a36Sopenharmony_ci		switch (fill_rop) {
20062306a36Sopenharmony_ci		case 0x00: /* blackness */
20162306a36Sopenharmony_ci		case 0x5A: /* pattern inversion */
20262306a36Sopenharmony_ci		case 0xF0: /* pattern copy */
20362306a36Sopenharmony_ci		case 0xFF: /* whiteness */
20462306a36Sopenharmony_ci			break;
20562306a36Sopenharmony_ci		default:
20662306a36Sopenharmony_ci			printk(KERN_WARNING "hw_bitblt_2: Invalid fill rop: "
20762306a36Sopenharmony_ci				"%u\n", fill_rop);
20862306a36Sopenharmony_ci			return -EINVAL;
20962306a36Sopenharmony_ci		}
21062306a36Sopenharmony_ci	}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	ret = viafb_set_bpp(engine, dst_bpp);
21362306a36Sopenharmony_ci	if (ret)
21462306a36Sopenharmony_ci		return ret;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	if (op == VIA_BITBLT_FILL)
21762306a36Sopenharmony_ci		tmp = 0;
21862306a36Sopenharmony_ci	else
21962306a36Sopenharmony_ci		tmp = src_pitch;
22062306a36Sopenharmony_ci	if (tmp & 0xFFFFC007 || dst_pitch & 0xFFFFC007) {
22162306a36Sopenharmony_ci		printk(KERN_WARNING "hw_bitblt_2: Unsupported pitch %X %X\n",
22262306a36Sopenharmony_ci			tmp, dst_pitch);
22362306a36Sopenharmony_ci		return -EINVAL;
22462306a36Sopenharmony_ci	}
22562306a36Sopenharmony_ci	tmp = (tmp >> 3) | (dst_pitch << (16 - 3));
22662306a36Sopenharmony_ci	writel(tmp, engine + 0x08);
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	if ((width - 1) & 0xFFFFF000 || (height - 1) & 0xFFFFF000) {
22962306a36Sopenharmony_ci		printk(KERN_WARNING "hw_bitblt_2: Unsupported width/height "
23062306a36Sopenharmony_ci			"%d %d\n", width, height);
23162306a36Sopenharmony_ci		return -EINVAL;
23262306a36Sopenharmony_ci	}
23362306a36Sopenharmony_ci	tmp = (width - 1) | ((height - 1) << 16);
23462306a36Sopenharmony_ci	writel(tmp, engine + 0x0C);
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	if (dst_x & 0xFFFFF000 || dst_y & 0xFFFFF000) {
23762306a36Sopenharmony_ci		printk(KERN_WARNING "hw_bitblt_2: Unsupported destination x/y "
23862306a36Sopenharmony_ci			"%d %d\n", dst_x, dst_y);
23962306a36Sopenharmony_ci		return -EINVAL;
24062306a36Sopenharmony_ci	}
24162306a36Sopenharmony_ci	tmp = dst_x | (dst_y << 16);
24262306a36Sopenharmony_ci	writel(tmp, engine + 0x10);
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	if (dst_addr & 0xE0000007) {
24562306a36Sopenharmony_ci		printk(KERN_WARNING "hw_bitblt_2: Unsupported destination "
24662306a36Sopenharmony_ci			"address %X\n", dst_addr);
24762306a36Sopenharmony_ci		return -EINVAL;
24862306a36Sopenharmony_ci	}
24962306a36Sopenharmony_ci	tmp = dst_addr >> 3;
25062306a36Sopenharmony_ci	writel(tmp, engine + 0x14);
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	if (op != VIA_BITBLT_FILL) {
25362306a36Sopenharmony_ci		if (src_x & (op == VIA_BITBLT_MONO ? 0xFFFF8000 : 0xFFFFF000)
25462306a36Sopenharmony_ci			|| src_y & 0xFFFFF000) {
25562306a36Sopenharmony_ci			printk(KERN_WARNING "hw_bitblt_2: Unsupported source "
25662306a36Sopenharmony_ci				"x/y %d %d\n", src_x, src_y);
25762306a36Sopenharmony_ci			return -EINVAL;
25862306a36Sopenharmony_ci		}
25962306a36Sopenharmony_ci		tmp = src_x | (src_y << 16);
26062306a36Sopenharmony_ci		writel(tmp, engine + 0x18);
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci		tmp = src_mem ? 0 : src_addr;
26362306a36Sopenharmony_ci		if (dst_addr & 0xE0000007) {
26462306a36Sopenharmony_ci			printk(KERN_WARNING "hw_bitblt_2: Unsupported source "
26562306a36Sopenharmony_ci				"address %X\n", tmp);
26662306a36Sopenharmony_ci			return -EINVAL;
26762306a36Sopenharmony_ci		}
26862306a36Sopenharmony_ci		tmp >>= 3;
26962306a36Sopenharmony_ci		writel(tmp, engine + 0x1C);
27062306a36Sopenharmony_ci	}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	if (op == VIA_BITBLT_FILL) {
27362306a36Sopenharmony_ci		writel(fg_color, engine + 0x58);
27462306a36Sopenharmony_ci	} else if (op == VIA_BITBLT_MONO) {
27562306a36Sopenharmony_ci		writel(fg_color, engine + 0x4C);
27662306a36Sopenharmony_ci		writel(bg_color, engine + 0x50);
27762306a36Sopenharmony_ci	}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	if (op == VIA_BITBLT_FILL)
28062306a36Sopenharmony_ci		ge_cmd |= fill_rop << 24 | 0x00002000 | 0x00000001;
28162306a36Sopenharmony_ci	else {
28262306a36Sopenharmony_ci		ge_cmd |= 0xCC000000; /* ROP=SRCCOPY */
28362306a36Sopenharmony_ci		if (src_mem)
28462306a36Sopenharmony_ci			ge_cmd |= 0x00000040;
28562306a36Sopenharmony_ci		if (op == VIA_BITBLT_MONO)
28662306a36Sopenharmony_ci			ge_cmd |= 0x00000002 | 0x00000100 | 0x00020000;
28762306a36Sopenharmony_ci		else
28862306a36Sopenharmony_ci			ge_cmd |= 0x00000001;
28962306a36Sopenharmony_ci	}
29062306a36Sopenharmony_ci	writel(ge_cmd, engine);
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	if (op == VIA_BITBLT_FILL || !src_mem)
29362306a36Sopenharmony_ci		return 0;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	tmp = (width * height * (op == VIA_BITBLT_MONO ? 1 : (dst_bpp >> 3)) +
29662306a36Sopenharmony_ci		3) >> 2;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	for (i = 0; i < tmp; i++)
29962306a36Sopenharmony_ci		writel(src_mem[i], engine + VIA_MMIO_BLTBASE);
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	return 0;
30262306a36Sopenharmony_ci}
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ciint viafb_setup_engine(struct fb_info *info)
30562306a36Sopenharmony_ci{
30662306a36Sopenharmony_ci	struct viafb_par *viapar = info->par;
30762306a36Sopenharmony_ci	void __iomem *engine;
30862306a36Sopenharmony_ci	u32 chip_name = viapar->shared->chip_info.gfx_chip_name;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	engine = viapar->shared->vdev->engine_mmio;
31162306a36Sopenharmony_ci	if (!engine) {
31262306a36Sopenharmony_ci		printk(KERN_WARNING "viafb_init_accel: ioremap failed, "
31362306a36Sopenharmony_ci			"hardware acceleration disabled\n");
31462306a36Sopenharmony_ci		return -ENOMEM;
31562306a36Sopenharmony_ci	}
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	switch (chip_name) {
31862306a36Sopenharmony_ci	case UNICHROME_CLE266:
31962306a36Sopenharmony_ci	case UNICHROME_K400:
32062306a36Sopenharmony_ci	case UNICHROME_K800:
32162306a36Sopenharmony_ci	case UNICHROME_PM800:
32262306a36Sopenharmony_ci	case UNICHROME_CN700:
32362306a36Sopenharmony_ci	case UNICHROME_CX700:
32462306a36Sopenharmony_ci	case UNICHROME_CN750:
32562306a36Sopenharmony_ci	case UNICHROME_K8M890:
32662306a36Sopenharmony_ci	case UNICHROME_P4M890:
32762306a36Sopenharmony_ci	case UNICHROME_P4M900:
32862306a36Sopenharmony_ci		viapar->shared->hw_bitblt = hw_bitblt_1;
32962306a36Sopenharmony_ci		break;
33062306a36Sopenharmony_ci	case UNICHROME_VX800:
33162306a36Sopenharmony_ci	case UNICHROME_VX855:
33262306a36Sopenharmony_ci	case UNICHROME_VX900:
33362306a36Sopenharmony_ci		viapar->shared->hw_bitblt = hw_bitblt_2;
33462306a36Sopenharmony_ci		break;
33562306a36Sopenharmony_ci	default:
33662306a36Sopenharmony_ci		viapar->shared->hw_bitblt = NULL;
33762306a36Sopenharmony_ci	}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	viapar->fbmem_free -= CURSOR_SIZE;
34062306a36Sopenharmony_ci	viapar->shared->cursor_vram_addr = viapar->fbmem_free;
34162306a36Sopenharmony_ci	viapar->fbmem_used += CURSOR_SIZE;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	viapar->fbmem_free -= VQ_SIZE;
34462306a36Sopenharmony_ci	viapar->shared->vq_vram_addr = viapar->fbmem_free;
34562306a36Sopenharmony_ci	viapar->fbmem_used += VQ_SIZE;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_VIDEO_VIA_CAMERA)
34862306a36Sopenharmony_ci	/*
34962306a36Sopenharmony_ci	 * Set aside a chunk of framebuffer memory for the camera
35062306a36Sopenharmony_ci	 * driver.  Someday this driver probably needs a proper allocator
35162306a36Sopenharmony_ci	 * for fbmem; for now, we just have to do this before the
35262306a36Sopenharmony_ci	 * framebuffer initializes itself.
35362306a36Sopenharmony_ci	 *
35462306a36Sopenharmony_ci	 * As for the size: the engine can handle three frames,
35562306a36Sopenharmony_ci	 * 16 bits deep, up to VGA resolution.
35662306a36Sopenharmony_ci	 */
35762306a36Sopenharmony_ci	viapar->shared->vdev->camera_fbmem_size = 3*VGA_HEIGHT*VGA_WIDTH*2;
35862306a36Sopenharmony_ci	viapar->fbmem_free -= viapar->shared->vdev->camera_fbmem_size;
35962306a36Sopenharmony_ci	viapar->fbmem_used += viapar->shared->vdev->camera_fbmem_size;
36062306a36Sopenharmony_ci	viapar->shared->vdev->camera_fbmem_offset = viapar->fbmem_free;
36162306a36Sopenharmony_ci#endif
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	viafb_reset_engine(viapar);
36462306a36Sopenharmony_ci	return 0;
36562306a36Sopenharmony_ci}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_civoid viafb_reset_engine(struct viafb_par *viapar)
36862306a36Sopenharmony_ci{
36962306a36Sopenharmony_ci	void __iomem *engine = viapar->shared->vdev->engine_mmio;
37062306a36Sopenharmony_ci	int highest_reg, i;
37162306a36Sopenharmony_ci	u32 vq_start_addr, vq_end_addr, vq_start_low, vq_end_low, vq_high,
37262306a36Sopenharmony_ci		vq_len, chip_name = viapar->shared->chip_info.gfx_chip_name;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	/* Initialize registers to reset the 2D engine */
37562306a36Sopenharmony_ci	switch (viapar->shared->chip_info.twod_engine) {
37662306a36Sopenharmony_ci	case VIA_2D_ENG_M1:
37762306a36Sopenharmony_ci		highest_reg = 0x5c;
37862306a36Sopenharmony_ci		break;
37962306a36Sopenharmony_ci	default:
38062306a36Sopenharmony_ci		highest_reg = 0x40;
38162306a36Sopenharmony_ci		break;
38262306a36Sopenharmony_ci	}
38362306a36Sopenharmony_ci	for (i = 0; i <= highest_reg; i += 4)
38462306a36Sopenharmony_ci		writel(0x0, engine + i);
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	/* Init AGP and VQ regs */
38762306a36Sopenharmony_ci	switch (chip_name) {
38862306a36Sopenharmony_ci	case UNICHROME_K8M890:
38962306a36Sopenharmony_ci	case UNICHROME_P4M900:
39062306a36Sopenharmony_ci	case UNICHROME_VX800:
39162306a36Sopenharmony_ci	case UNICHROME_VX855:
39262306a36Sopenharmony_ci	case UNICHROME_VX900:
39362306a36Sopenharmony_ci		writel(0x00100000, engine + VIA_REG_CR_TRANSET);
39462306a36Sopenharmony_ci		writel(0x680A0000, engine + VIA_REG_CR_TRANSPACE);
39562306a36Sopenharmony_ci		writel(0x02000000, engine + VIA_REG_CR_TRANSPACE);
39662306a36Sopenharmony_ci		break;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	default:
39962306a36Sopenharmony_ci		writel(0x00100000, engine + VIA_REG_TRANSET);
40062306a36Sopenharmony_ci		writel(0x00000000, engine + VIA_REG_TRANSPACE);
40162306a36Sopenharmony_ci		writel(0x00333004, engine + VIA_REG_TRANSPACE);
40262306a36Sopenharmony_ci		writel(0x60000000, engine + VIA_REG_TRANSPACE);
40362306a36Sopenharmony_ci		writel(0x61000000, engine + VIA_REG_TRANSPACE);
40462306a36Sopenharmony_ci		writel(0x62000000, engine + VIA_REG_TRANSPACE);
40562306a36Sopenharmony_ci		writel(0x63000000, engine + VIA_REG_TRANSPACE);
40662306a36Sopenharmony_ci		writel(0x64000000, engine + VIA_REG_TRANSPACE);
40762306a36Sopenharmony_ci		writel(0x7D000000, engine + VIA_REG_TRANSPACE);
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci		writel(0xFE020000, engine + VIA_REG_TRANSET);
41062306a36Sopenharmony_ci		writel(0x00000000, engine + VIA_REG_TRANSPACE);
41162306a36Sopenharmony_ci		break;
41262306a36Sopenharmony_ci	}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	/* Enable VQ */
41562306a36Sopenharmony_ci	vq_start_addr = viapar->shared->vq_vram_addr;
41662306a36Sopenharmony_ci	vq_end_addr = viapar->shared->vq_vram_addr + VQ_SIZE - 1;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	vq_start_low = 0x50000000 | (vq_start_addr & 0xFFFFFF);
41962306a36Sopenharmony_ci	vq_end_low = 0x51000000 | (vq_end_addr & 0xFFFFFF);
42062306a36Sopenharmony_ci	vq_high = 0x52000000 | ((vq_start_addr & 0xFF000000) >> 24) |
42162306a36Sopenharmony_ci		((vq_end_addr & 0xFF000000) >> 16);
42262306a36Sopenharmony_ci	vq_len = 0x53000000 | (VQ_SIZE >> 3);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	switch (chip_name) {
42562306a36Sopenharmony_ci	case UNICHROME_K8M890:
42662306a36Sopenharmony_ci	case UNICHROME_P4M900:
42762306a36Sopenharmony_ci	case UNICHROME_VX800:
42862306a36Sopenharmony_ci	case UNICHROME_VX855:
42962306a36Sopenharmony_ci	case UNICHROME_VX900:
43062306a36Sopenharmony_ci		vq_start_low |= 0x20000000;
43162306a36Sopenharmony_ci		vq_end_low |= 0x20000000;
43262306a36Sopenharmony_ci		vq_high |= 0x20000000;
43362306a36Sopenharmony_ci		vq_len |= 0x20000000;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci		writel(0x00100000, engine + VIA_REG_CR_TRANSET);
43662306a36Sopenharmony_ci		writel(vq_high, engine + VIA_REG_CR_TRANSPACE);
43762306a36Sopenharmony_ci		writel(vq_start_low, engine + VIA_REG_CR_TRANSPACE);
43862306a36Sopenharmony_ci		writel(vq_end_low, engine + VIA_REG_CR_TRANSPACE);
43962306a36Sopenharmony_ci		writel(vq_len, engine + VIA_REG_CR_TRANSPACE);
44062306a36Sopenharmony_ci		writel(0x74301001, engine + VIA_REG_CR_TRANSPACE);
44162306a36Sopenharmony_ci		writel(0x00000000, engine + VIA_REG_CR_TRANSPACE);
44262306a36Sopenharmony_ci		break;
44362306a36Sopenharmony_ci	default:
44462306a36Sopenharmony_ci		writel(0x00FE0000, engine + VIA_REG_TRANSET);
44562306a36Sopenharmony_ci		writel(0x080003FE, engine + VIA_REG_TRANSPACE);
44662306a36Sopenharmony_ci		writel(0x0A00027C, engine + VIA_REG_TRANSPACE);
44762306a36Sopenharmony_ci		writel(0x0B000260, engine + VIA_REG_TRANSPACE);
44862306a36Sopenharmony_ci		writel(0x0C000274, engine + VIA_REG_TRANSPACE);
44962306a36Sopenharmony_ci		writel(0x0D000264, engine + VIA_REG_TRANSPACE);
45062306a36Sopenharmony_ci		writel(0x0E000000, engine + VIA_REG_TRANSPACE);
45162306a36Sopenharmony_ci		writel(0x0F000020, engine + VIA_REG_TRANSPACE);
45262306a36Sopenharmony_ci		writel(0x1000027E, engine + VIA_REG_TRANSPACE);
45362306a36Sopenharmony_ci		writel(0x110002FE, engine + VIA_REG_TRANSPACE);
45462306a36Sopenharmony_ci		writel(0x200F0060, engine + VIA_REG_TRANSPACE);
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci		writel(0x00000006, engine + VIA_REG_TRANSPACE);
45762306a36Sopenharmony_ci		writel(0x40008C0F, engine + VIA_REG_TRANSPACE);
45862306a36Sopenharmony_ci		writel(0x44000000, engine + VIA_REG_TRANSPACE);
45962306a36Sopenharmony_ci		writel(0x45080C04, engine + VIA_REG_TRANSPACE);
46062306a36Sopenharmony_ci		writel(0x46800408, engine + VIA_REG_TRANSPACE);
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci		writel(vq_high, engine + VIA_REG_TRANSPACE);
46362306a36Sopenharmony_ci		writel(vq_start_low, engine + VIA_REG_TRANSPACE);
46462306a36Sopenharmony_ci		writel(vq_end_low, engine + VIA_REG_TRANSPACE);
46562306a36Sopenharmony_ci		writel(vq_len, engine + VIA_REG_TRANSPACE);
46662306a36Sopenharmony_ci		break;
46762306a36Sopenharmony_ci	}
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	/* Set Cursor Image Base Address */
47062306a36Sopenharmony_ci	writel(viapar->shared->cursor_vram_addr, engine + VIA_REG_CURSOR_MODE);
47162306a36Sopenharmony_ci	writel(0x0, engine + VIA_REG_CURSOR_POS);
47262306a36Sopenharmony_ci	writel(0x0, engine + VIA_REG_CURSOR_ORG);
47362306a36Sopenharmony_ci	writel(0x0, engine + VIA_REG_CURSOR_BG);
47462306a36Sopenharmony_ci	writel(0x0, engine + VIA_REG_CURSOR_FG);
47562306a36Sopenharmony_ci	return;
47662306a36Sopenharmony_ci}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_civoid viafb_show_hw_cursor(struct fb_info *info, int Status)
47962306a36Sopenharmony_ci{
48062306a36Sopenharmony_ci	struct viafb_par *viapar = info->par;
48162306a36Sopenharmony_ci	u32 temp, iga_path = viapar->iga_path;
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	temp = readl(viapar->shared->vdev->engine_mmio + VIA_REG_CURSOR_MODE);
48462306a36Sopenharmony_ci	switch (Status) {
48562306a36Sopenharmony_ci	case HW_Cursor_ON:
48662306a36Sopenharmony_ci		temp |= 0x1;
48762306a36Sopenharmony_ci		break;
48862306a36Sopenharmony_ci	case HW_Cursor_OFF:
48962306a36Sopenharmony_ci		temp &= 0xFFFFFFFE;
49062306a36Sopenharmony_ci		break;
49162306a36Sopenharmony_ci	}
49262306a36Sopenharmony_ci	switch (iga_path) {
49362306a36Sopenharmony_ci	case IGA2:
49462306a36Sopenharmony_ci		temp |= 0x80000000;
49562306a36Sopenharmony_ci		break;
49662306a36Sopenharmony_ci	case IGA1:
49762306a36Sopenharmony_ci	default:
49862306a36Sopenharmony_ci		temp &= 0x7FFFFFFF;
49962306a36Sopenharmony_ci	}
50062306a36Sopenharmony_ci	writel(temp, viapar->shared->vdev->engine_mmio + VIA_REG_CURSOR_MODE);
50162306a36Sopenharmony_ci}
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_civoid viafb_wait_engine_idle(struct fb_info *info)
50462306a36Sopenharmony_ci{
50562306a36Sopenharmony_ci	struct viafb_par *viapar = info->par;
50662306a36Sopenharmony_ci	int loop = 0;
50762306a36Sopenharmony_ci	u32 mask;
50862306a36Sopenharmony_ci	void __iomem *engine = viapar->shared->vdev->engine_mmio;
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	switch (viapar->shared->chip_info.twod_engine) {
51162306a36Sopenharmony_ci	case VIA_2D_ENG_H5:
51262306a36Sopenharmony_ci	case VIA_2D_ENG_M1:
51362306a36Sopenharmony_ci		mask = VIA_CMD_RGTR_BUSY_M1 | VIA_2D_ENG_BUSY_M1 |
51462306a36Sopenharmony_ci			      VIA_3D_ENG_BUSY_M1;
51562306a36Sopenharmony_ci		break;
51662306a36Sopenharmony_ci	default:
51762306a36Sopenharmony_ci		while (!(readl(engine + VIA_REG_STATUS) &
51862306a36Sopenharmony_ci				VIA_VR_QUEUE_BUSY) && (loop < MAXLOOP)) {
51962306a36Sopenharmony_ci			loop++;
52062306a36Sopenharmony_ci			cpu_relax();
52162306a36Sopenharmony_ci		}
52262306a36Sopenharmony_ci		mask = VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | VIA_3D_ENG_BUSY;
52362306a36Sopenharmony_ci		break;
52462306a36Sopenharmony_ci	}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	while ((readl(engine + VIA_REG_STATUS) & mask) && (loop < MAXLOOP)) {
52762306a36Sopenharmony_ci		loop++;
52862306a36Sopenharmony_ci		cpu_relax();
52962306a36Sopenharmony_ci	}
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	if (loop >= MAXLOOP)
53262306a36Sopenharmony_ci		printk(KERN_ERR "viafb_wait_engine_idle: not syncing\n");
53362306a36Sopenharmony_ci}
534